From: Kostya Serebryany Date: Fri, 7 Dec 2012 15:15:01 +0000 (+0000) Subject: [asan] intercept prctl(PR_SET_NAME) and set the thread name. Output the thread names... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e7108227ca3a7a2d98f07c34c263725674b83a5f;p=platform%2Fupstream%2Fllvm.git [asan] intercept prctl(PR_SET_NAME) and set the thread name. Output the thread names (if non-empty) in asan reports llvm-svn: 169601 --- diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index efd4bc5..ef5f345 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -177,6 +177,23 @@ INTERCEPTOR(void, siglongjmp, void *env, int val) { } #endif +#define PR_SET_NAME 15 + +INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) { + int res = REAL(prctl(option, arg2, arg3, arg4, arg5)); + if (option == PR_SET_NAME) { + AsanThread *t = asanThreadRegistry().GetCurrent(); + if (t) { + char buff[17]; + internal_strncpy(buff, (char*)arg2, 16); + buff[16] = 0; + t->summary()->set_name(buff); + } + } + return res; +} + #if ASAN_INTERCEPT___CXA_THROW INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { CHECK(REAL(__cxa_throw)); @@ -720,6 +737,7 @@ void InitializeAsanInterceptors() { #if ASAN_INTERCEPT_SIGLONGJMP ASAN_INTERCEPT_FUNC(siglongjmp); #endif + ASAN_INTERCEPT_FUNC(prctl); // Intercept exception handling functions. #if ASAN_INTERCEPT___CXA_THROW diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 2627919..266ca03 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -203,6 +203,25 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr, (void*)(chunk.Beg()), (void*)(chunk.End())); } +// Return " (thread_name) " or an empty string if the name is empty. +const char *ThreadNameWithParenthesis(AsanThreadSummary *t, char buff[], + uptr buff_len) { + const char *name = t->name(); + if (*name == 0) return ""; + buff[0] = 0; + internal_strncat(buff, " (", 3); + internal_strncat(buff, name, buff_len - 4); + internal_strncat(buff, ")", 2); + return buff; +} + +const char *ThreadNameWithParenthesis(u32 tid, char buff[], + uptr buff_len) { + if (tid == kInvalidTid) return ""; + AsanThreadSummary *t = asanThreadRegistry().FindByTid(tid); + return ThreadNameWithParenthesis(t, buff, buff_len); +} + void DescribeHeapAddress(uptr addr, uptr access_size) { AsanChunkView chunk = FindHeapChunkByAddress(addr); if (!chunk.IsValid()) return; @@ -214,20 +233,25 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { chunk.GetAllocStack(&alloc_stack); AsanThread *t = asanThreadRegistry().GetCurrent(); CHECK(t); + char tname[128]; if (chunk.FreeTid() != kInvalidTid) { AsanThreadSummary *free_thread = asanThreadRegistry().FindByTid(chunk.FreeTid()); - Printf("freed by thread T%d here:\n", free_thread->tid()); + Printf("freed by thread T%d%s here:\n", free_thread->tid(), + ThreadNameWithParenthesis(free_thread, tname, sizeof(tname))); StackTrace free_stack; chunk.GetFreeStack(&free_stack); PrintStack(&free_stack); - Printf("previously allocated by thread T%d here:\n", alloc_thread->tid()); + Printf("previously allocated by thread T%d%s here:\n", + alloc_thread->tid(), + ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname))); PrintStack(&alloc_stack); DescribeThread(t->summary()); DescribeThread(free_thread); DescribeThread(alloc_thread); } else { - Printf("allocated by thread T%d here:\n", alloc_thread->tid()); + Printf("allocated by thread T%d%s here:\n", alloc_thread->tid(), + ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname))); PrintStack(&alloc_stack); DescribeThread(t->summary()); DescribeThread(alloc_thread); @@ -256,8 +280,13 @@ void DescribeThread(AsanThreadSummary *summary) { return; } summary->set_announced(true); - Printf("Thread T%d created by T%d here:\n", - summary->tid(), summary->parent_tid()); + char tname[128]; + Printf("Thread T%d%s", summary->tid(), + ThreadNameWithParenthesis(summary->tid(), tname, sizeof(tname))); + Printf(" created by T%d%s here:\n", + summary->parent_tid(), + ThreadNameWithParenthesis(summary->parent_tid(), + tname, sizeof(tname))); PrintStack(summary->stack()); // Recursively described parent thread if needed. if (flags()->print_full_thread_history) { @@ -471,9 +500,11 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, bug_descr, (void*)addr, pc, bp, sp); u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); - Printf("%s of size %zu at %p thread T%d\n", + char tname[128]; + Printf("%s of size %zu at %p thread T%d%s\n", access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", - access_size, (void*)addr, curr_tid); + access_size, (void*)addr, curr_tid, + ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); PrintStack(&stack); diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index 4d4c439..acc27e5 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -39,6 +39,7 @@ class AsanThreadSummary { internal_memcpy(&stack_, stack, sizeof(*stack)); } thread_ = 0; + name_[0] = 0; } u32 tid() { return tid_; } void set_tid(u32 tid) { tid_ = tid; } @@ -49,6 +50,10 @@ class AsanThreadSummary { AsanThread *thread() { return thread_; } void set_thread(AsanThread *thread) { thread_ = thread; } static void TSDDtor(void *tsd); + void set_name(const char *name) { + internal_strncpy(name_, name, sizeof(name_) - 1); + } + const char *name() { return name_; } private: u32 tid_; @@ -56,8 +61,12 @@ class AsanThreadSummary { bool announced_; StackTrace stack_; AsanThread *thread_; + char name_[128]; }; +// AsanThreadSummary objects are never freed, so we need many of them. +COMPILER_CHECK(sizeof(AsanThreadSummary) <= 4094); + // AsanThread are stored in TSD and destroyed when the thread dies. class AsanThread { public: diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc index db226e5..a114580 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cc +++ b/compiler-rt/lib/asan/tests/asan_test.cc @@ -20,6 +20,10 @@ #include #include +#ifdef __linux__ +# include +#endif + #if defined(__i386__) || defined(__x86_64__) #include #endif @@ -1619,19 +1623,28 @@ TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) { "malloc_fff.*malloc_eee.*malloc_ddd"); } +static void TryToSetThreadName(const char *name) { +#ifdef __linux__ + prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); +#endif +} + void *ThreadedTestAlloc(void *a) { + TryToSetThreadName("AllocThr"); int **p = (int**)a; *p = new int; return 0; } void *ThreadedTestFree(void *a) { + TryToSetThreadName("FreeThr"); int **p = (int**)a; delete *p; return 0; } void *ThreadedTestUse(void *a) { + TryToSetThreadName("UseThr"); int **p = (int**)a; **p = 1; return 0; @@ -1656,6 +1669,22 @@ TEST(AddressSanitizer, ThreadedTest) { ".*Thread T.*created"); } +#ifdef __linux__ +TEST(AddressSanitizer, ThreadNamesTest) { + // ThreadedTestSpawn(); + EXPECT_DEATH(ThreadedTestSpawn(), + ASAN_PCRE_DOTALL + "WRITE .*thread T3 .UseThr." + ".*freed by thread T2 .FreeThr. here:" + ".*previously allocated by thread T1 .AllocThr. here:" + ".*Thread T3 .UseThr. created by T0 here:" + ".*Thread T2 .FreeThr. created by T0 here:" + ".*Thread T1 .AllocThr. created by T0 here:" + ""); + +} +#endif + #if ASAN_NEEDS_SEGV TEST(AddressSanitizer, ShadowGapTest) { #if SANITIZER_WORDSIZE == 32