diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp @@ -54,6 +54,23 @@ static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; static JavaContext *jctx; +MBlock *JavaHeapBlock(uptr addr, uptr *start) { + if (!jctx || addr < jctx->heap_begin || + addr >= jctx->heap_begin + jctx->heap_size) + return nullptr; + for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin; + p -= kMetaShadowCell) { + MBlock *b = ctx->metamap.GetBlock(p); + if (!b) + continue; + if (p + b->siz <= addr) + return nullptr; + *start = p; + return b; + } + return nullptr; +} + } // namespace __tsan #define SCOPED_JAVA_FUNC(func) \ diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -683,6 +683,7 @@ ReportStack *SymbolizeStackId(u32 stack_id); void PrintCurrentStack(ThreadState *thr, uptr pc); void PrintCurrentStackSlow(uptr pc); // uses libunwind +MBlock *JavaHeapBlock(uptr addr, uptr *start); void Initialize(ThreadState *thr); void MaybeSpawnBackgroundThread(); diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp @@ -337,12 +337,15 @@ return; } MBlock *b = 0; + uptr block_begin = 0; Allocator *a = allocator(); if (a->PointerIsMine((void*)addr)) { - void *block_begin = a->GetBlockBegin((void*)addr); + block_begin = (uptr)a->GetBlockBegin((void *)addr); if (block_begin) - b = ctx->metamap.GetBlock((uptr)block_begin); + b = ctx->metamap.GetBlock(block_begin); } + if (!b) + b = JavaHeapBlock(addr, &block_begin); if (b != 0) { ThreadContext *tctx = FindThreadByTidLocked(b->tid); ReportLocation *loc = ReportLocation::New(ReportLocationHeap); diff --git a/compiler-rt/test/tsan/java.h b/compiler-rt/test/tsan/java.h --- a/compiler-rt/test/tsan/java.h +++ b/compiler-rt/test/tsan/java.h @@ -22,6 +22,8 @@ void __tsan_read1_pc(jptr addr, jptr pc); void __tsan_write1_pc(jptr addr, jptr pc); +void __tsan_func_entry(jptr pc); +void __tsan_func_exit(); } const jptr kExternalPCBit = 1ULL << 60; diff --git a/compiler-rt/test/tsan/java_symbolization.cpp b/compiler-rt/test/tsan/java_symbolization.cpp --- a/compiler-rt/test/tsan/java_symbolization.cpp +++ b/compiler-rt/test/tsan/java_symbolization.cpp @@ -9,24 +9,40 @@ add_frame(ctx, "MyInnerFunc", "MyInnerFile.java", 1234, 56); add_frame(ctx, "MyOuterFunc", "MyOuterFile.java", 4321, 65); } + if (pc == (2345 | kExternalPCBit)) { + add_frame(ctx, "Caller1", "CallerFile.java", 111, 22); + add_frame(ctx, "Caller2", "CallerFile.java", 333, 44); + } + if (pc == (3456 | kExternalPCBit)) { + add_frame(ctx, "Allocer1", "Alloc.java", 11, 222); + add_frame(ctx, "Allocer2", "Alloc.java", 33, 444); + } } void *Thread(void *p) { barrier_wait(&barrier); - __tsan_write1_pc((jptr)p, 1234 | kExternalPCBit); + __tsan_func_entry(2345 | kExternalPCBit); + __tsan_write1_pc((jptr)p + 16, 1234 | kExternalPCBit); + __tsan_func_exit(); return 0; } +jptr const kHeapSize = 64 * 1024; +jptr java_heap[kHeapSize]; + int main() { barrier_init(&barrier, 2); - int const kHeapSize = 1024 * 1024; - jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; + jptr jheap = (jptr)java_heap; __tsan_java_init(jheap, kHeapSize); - const int kBlockSize = 16; + const int kBlockSize = 32; + __tsan_func_entry(3456 | kExternalPCBit); __tsan_java_alloc(jheap, kBlockSize); + __tsan_func_exit(); pthread_t th; pthread_create(&th, 0, Thread, (void*)jheap); - __tsan_write1_pc((jptr)jheap, 1234 | kExternalPCBit); + __tsan_func_entry(2345 | kExternalPCBit); + __tsan_write1_pc(jheap + 16, 1234 | kExternalPCBit); + __tsan_func_exit(); barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(jheap, kBlockSize); @@ -35,6 +51,24 @@ } // CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write +// CHECK: #0 MyInnerFunc MyInnerFile.java:1234:56 +// CHECK: #1 MyOuterFunc MyOuterFile.java:4321:65 +// CHECK: #2 Caller1 CallerFile.java:111:22 +// CHECK: #3 Caller2 CallerFile.java:333:44 +// CHECK-NOT: #4 +// CHECK: Previous write // CHECK: #0 MyInnerFunc MyInnerFile.java:1234:56 // CHECK: #1 MyOuterFunc MyOuterFile.java:4321:65 +// CHECK: #2 Caller1 CallerFile.java:111:22 +// CHECK: #3 Caller2 CallerFile.java:333:44 +// On Linux/glibc #4 is __libc_start_main, but can be something else elsewhere. +// CHECK: #4 +// CHECK: Location is heap block of size 32 at {{.*}} allocated by main thread: +// CHECK: #0 __tsan_java_alloc +// CHECK: #1 main +// CHECK: #2 Allocer1 Alloc.java:11:222 +// CHECK: #3 Allocer2 Alloc.java:33:444 +// On Linux/glibc #4 is __libc_start_main, but can be something else elsewhere. +// CHECK: #4 // CHECK: DONE