diff --git a/compiler-rt/lib/tsan/lit_tests/java_lock_move.cc b/compiler-rt/lib/tsan/lit_tests/java_lock_move.cc new file mode 100644 index 000000000000..3b30085b142e --- /dev/null +++ b/compiler-rt/lib/tsan/lit_tests/java_lock_move.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s +#include +#include +#include + +extern "C" { +typedef unsigned long jptr; // NOLINT +void __tsan_java_init(jptr heap_begin, jptr heap_size); +int __tsan_java_fini(); +void __tsan_java_alloc(jptr ptr, jptr size); +void __tsan_java_free(jptr ptr, jptr size); +void __tsan_java_move(jptr src, jptr dst, jptr size); +void __tsan_java_mutex_lock(jptr addr); +void __tsan_java_mutex_unlock(jptr addr); +void __tsan_java_mutex_read_lock(jptr addr); +void __tsan_java_mutex_read_unlock(jptr addr); +} + +jptr varaddr; +jptr lockaddr; +jptr varaddr2; +jptr lockaddr2; + +void *Thread(void *p) { + sleep(1); + __tsan_java_mutex_lock(lockaddr2); + *(int*)varaddr2 = 42; + __tsan_java_mutex_unlock(lockaddr2); + return 0; +} + +int main() { + int const kHeapSize = 1024 * 1024; + void *jheap = malloc(kHeapSize); + __tsan_java_init((jptr)jheap, kHeapSize); + const int kBlockSize = 64; + int const kMove = 1024; + __tsan_java_alloc((jptr)jheap, kBlockSize); + varaddr = (jptr)jheap; + lockaddr = (jptr)jheap + 46; + varaddr2 = varaddr + kMove; + lockaddr2 = lockaddr + kMove; + pthread_t th; + pthread_create(&th, 0, Thread, 0); + __tsan_java_mutex_lock(lockaddr); + *(int*)varaddr = 43; + __tsan_java_mutex_unlock(lockaddr); + __tsan_java_move(varaddr, varaddr2, kBlockSize); + pthread_join(th, 0); + __tsan_java_free(varaddr2, kBlockSize); + return __tsan_java_fini(); +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc index 2bebed8eb218..e425c75800be 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc @@ -37,14 +37,6 @@ struct BlockDesc { begin = true; } - explicit BlockDesc(BlockDesc *b) - : mtx(MutexTypeJavaMBlock, StatMtxJavaMBlock) - , head(b->head) { - CHECK_EQ(begin, false); - begin = true; - b->head = 0; - } - ~BlockDesc() { CHECK_EQ(begin, true); begin = false; @@ -108,6 +100,14 @@ static BlockDesc *getblock(uptr addr) { return &jctx->heap_shadow[i]; } +static uptr USED getmem(BlockDesc *b) { + uptr i = b - jctx->heap_shadow; + uptr p = jctx->heap_begin + i * kHeapAlignment; + CHECK_GE(p, jctx->heap_begin); + CHECK_LT(p, jctx->heap_begin + jctx->heap_size); + return p; +} + static BlockDesc *getblockbegin(uptr addr) { for (BlockDesc *b = getblock(addr);; b--) { CHECK_GE(b, jctx->heap_shadow); @@ -123,13 +123,17 @@ SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr, || addr >= jctx->heap_begin + jctx->heap_size) return 0; BlockDesc *b = getblockbegin(addr); + DPrintf("#%d: GetJavaSync %p->%p\n", thr->tid, addr, b); Lock l(&b->mtx); SyncVar *s = b->head; for (; s; s = s->next) { - if (s->addr == addr) + if (s->addr == addr) { + DPrintf("#%d: found existing sync for %p\n", thr->tid, addr); break; + } } if (s == 0 && create) { + DPrintf("#%d: creating new sync for %p\n", thr->tid, addr); s = CTX()->synctab.Create(thr, pc, addr); s->next = b->head; b->head = s; @@ -233,8 +237,17 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) { BlockDesc *d = getblock(dst); BlockDesc *send = getblock(src + size); for (; s != send; s++, d++) { + CHECK_EQ(d->begin, false); if (s->begin) { - new(d) BlockDesc(s); + DPrintf("#%d: moving block %p->%p\n", thr->tid, getmem(s), getmem(d)); + new(d) BlockDesc; + d->head = s->head; + for (SyncVar *sync = d->head; sync; sync = sync->next) { + uptr newaddr = sync->addr - src + dst; + DPrintf("#%d: moving sync %p->%p\n", thr->tid, sync->addr, newaddr); + sync->addr = newaddr; + } + s->head = 0; s->~BlockDesc(); } } diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.h b/compiler-rt/lib/tsan/rtl/tsan_sync.h index f00038db5ef1..77749e22ffc2 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_sync.h +++ b/compiler-rt/lib/tsan/rtl/tsan_sync.h @@ -55,7 +55,7 @@ struct SyncVar { static const int kInvalidTid = -1; Mutex mtx; - const uptr addr; + uptr addr; const u64 uid; // Globally unique id. SyncClock clock; SyncClock read_clock; // Used for rw mutexes only.