[ASan] Add print_full_thread_history runtime option (on by default) that prints all full thread creation paths for threads involved in ASan error report

llvm-svn: 163200
This commit is contained in:
Alexey Samsonov 2012-09-05 07:37:15 +00:00
parent 2fa38f8ce0
commit c402cb62fd
7 changed files with 101 additions and 15 deletions

View File

@ -609,14 +609,14 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
alloc_thread->tid());
PrintStack(&alloc_stack);
t->summary()->Announce();
free_thread->Announce();
alloc_thread->Announce();
DescribeThread(t->summary());
DescribeThread(free_thread);
DescribeThread(alloc_thread);
} else {
Printf("allocated by thread T%d here:\n", alloc_thread->tid());
PrintStack(&alloc_stack);
t->summary()->Announce();
alloc_thread->Announce();
DescribeThread(t->summary());
DescribeThread(alloc_thread);
}
}

View File

@ -89,6 +89,10 @@ struct Flags {
bool allow_reexec;
// Strips this prefix from file paths in error reports.
const char *strip_path_prefix;
// If set, prints not only thread creation stacks for threads in error report,
// but also thread creation stacks for threads that created those threads,
// etc. up to main thread.
bool print_full_thread_history;
};
Flags *flags();

View File

@ -184,7 +184,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
Printf("HINT: this may be a false positive if your program uses "
"some custom stack unwind mechanism\n"
" (longjmp and C++ exceptions *are* supported)\n");
t->summary()->Announce();
DescribeThread(t->summary());
return true;
}
@ -201,6 +201,26 @@ void DescribeAddress(uptr addr, uptr access_size) {
DescribeHeapAddress(addr, access_size);
}
// ------------------- Thread description -------------------- {{{1
void DescribeThread(AsanThreadSummary *summary) {
CHECK(summary);
// No need to announce the main thread.
if (summary->tid() == 0 || summary->announced()) {
return;
}
summary->set_announced(true);
Printf("Thread T%d created by T%d here:\n",
summary->tid(), summary->parent_tid());
PrintStack(summary->stack());
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadSummary *parent_summary =
asanThreadRegistry().FindByTid(summary->parent_tid());
DescribeThread(parent_summary);
}
}
// -------------------- Different kinds of reports ----------------- {{{1
// Use ScopedInErrorReport to run common actions just before and
@ -238,7 +258,7 @@ class ScopedInErrorReport {
// Make sure the current thread is announced.
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
if (curr_thread) {
curr_thread->summary()->Announce();
DescribeThread(curr_thread->summary());
}
// Print memory stats.
__asan_print_accumulated_stats();

View File

@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
#include "asan_thread.h"
#include "sanitizer/asan_interface.h"
namespace __asan {
@ -27,6 +28,8 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size);
// Determines memory type on its own.
void DescribeAddress(uptr addr, uptr access_size);
void DescribeThread(AsanThreadSummary *summary);
// Different kinds of error reports.
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack);

View File

@ -102,6 +102,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->disable_core, "disable_core");
ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
ParseFlag(str, &f->allow_reexec, "allow_reexec");
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
}
extern "C" {
@ -139,6 +140,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->disable_core = (__WORDSIZE == 64);
f->strip_path_prefix = "";
f->allow_reexec = true;
f->print_full_thread_history = true;
// Override from user-specified string.
ParseFlagsFromString(f, __asan_default_options());

View File

@ -40,16 +40,12 @@ class AsanThreadSummary {
}
thread_ = 0;
}
void Announce() {
if (tid_ == 0) return; // no need to announce the main thread.
if (!announced_) {
announced_ = true;
Printf("Thread T%d created by T%d here:\n", tid_, parent_tid_);
PrintStack(&stack_);
}
}
u32 tid() { return tid_; }
void set_tid(u32 tid) { tid_ = tid; }
u32 parent_tid() { return parent_tid_; }
bool announced() { return announced_; }
void set_announced(bool announced) { announced_ = announced; }
StackTrace *stack() { return &stack_; }
AsanThread *thread() { return thread_; }
void set_thread(AsanThread *thread) { thread_ = thread; }
static void TSDDtor(void *tsd);

View File

@ -0,0 +1,61 @@
// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
#include <pthread.h>
int *x;
void *AllocThread(void *arg) {
x = new int;
*x = 42;
return NULL;
}
void *FreeThread(void *arg) {
delete x;
return NULL;
}
void *AccessThread(void *arg) {
*x = 43; // BOOM
return NULL;
}
typedef void* (*callback_type)(void* arg);
void *RunnerThread(void *function) {
pthread_t thread;
pthread_create(&thread, NULL, (callback_type)function, NULL);
pthread_join(thread, NULL);
return NULL;
}
void RunThread(callback_type function) {
pthread_t runner;
pthread_create(&runner, NULL, RunnerThread, (void*)function);
pthread_join(runner, NULL);
}
int main(int argc, char *argv[]) {
RunThread(AllocThread);
RunThread(FreeThread);
RunThread(AccessThread);
return (x != 0);
}
// CHECK: AddressSanitizer heap-use-after-free
// CHECK: WRITE of size 4 at 0x{{.*}} thread T[[ACCESS_THREAD:[0-9]+]]
// CHECK: freed by thread T[[FREE_THREAD:[0-9]+]] here:
// CHECK: previously allocated by thread T[[ALLOC_THREAD:[0-9]+]] here:
// CHECK: Thread T[[ACCESS_THREAD]] created by T[[ACCESS_RUNNER:[0-9]+]] here:
// CHECK: Thread T[[ACCESS_RUNNER]] created by T0 here:
// CHECK: Thread T[[FREE_THREAD]] created by T[[FREE_RUNNER:[0-9]+]] here:
// CHECK: Thread T[[FREE_RUNNER]] created by T0 here:
// CHECK: Thread T[[ALLOC_THREAD]] created by T[[ALLOC_RUNNER:[0-9]+]] here:
// CHECK: Thread T[[ALLOC_RUNNER]] created by T0 here: