}
#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));
#if ASAN_INTERCEPT_SIGLONGJMP
ASAN_INTERCEPT_FUNC(siglongjmp);
#endif
+ ASAN_INTERCEPT_FUNC(prctl);
// Intercept exception handling functions.
#if ASAN_INTERCEPT___CXA_THROW
(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;
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);
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) {
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);
#include <setjmp.h>
#include <assert.h>
+#ifdef __linux__
+# include <sys/prctl.h>
+#endif
+
#if defined(__i386__) || defined(__x86_64__)
#include <emmintrin.h>
#endif
"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;
".*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