tsan: fix Java memory move operations and add the test
llvm-svn: 170891
This commit is contained in:
parent
92e37d31e7
commit
a33bf2701e
|
@ -0,0 +1,54 @@
|
||||||
|
// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
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
|
|
@ -37,14 +37,6 @@ struct BlockDesc {
|
||||||
begin = true;
|
begin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit BlockDesc(BlockDesc *b)
|
|
||||||
: mtx(MutexTypeJavaMBlock, StatMtxJavaMBlock)
|
|
||||||
, head(b->head) {
|
|
||||||
CHECK_EQ(begin, false);
|
|
||||||
begin = true;
|
|
||||||
b->head = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~BlockDesc() {
|
~BlockDesc() {
|
||||||
CHECK_EQ(begin, true);
|
CHECK_EQ(begin, true);
|
||||||
begin = false;
|
begin = false;
|
||||||
|
@ -108,6 +100,14 @@ static BlockDesc *getblock(uptr addr) {
|
||||||
return &jctx->heap_shadow[i];
|
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) {
|
static BlockDesc *getblockbegin(uptr addr) {
|
||||||
for (BlockDesc *b = getblock(addr);; b--) {
|
for (BlockDesc *b = getblock(addr);; b--) {
|
||||||
CHECK_GE(b, jctx->heap_shadow);
|
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)
|
|| addr >= jctx->heap_begin + jctx->heap_size)
|
||||||
return 0;
|
return 0;
|
||||||
BlockDesc *b = getblockbegin(addr);
|
BlockDesc *b = getblockbegin(addr);
|
||||||
|
DPrintf("#%d: GetJavaSync %p->%p\n", thr->tid, addr, b);
|
||||||
Lock l(&b->mtx);
|
Lock l(&b->mtx);
|
||||||
SyncVar *s = b->head;
|
SyncVar *s = b->head;
|
||||||
for (; s; s = s->next) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (s == 0 && create) {
|
if (s == 0 && create) {
|
||||||
|
DPrintf("#%d: creating new sync for %p\n", thr->tid, addr);
|
||||||
s = CTX()->synctab.Create(thr, pc, addr);
|
s = CTX()->synctab.Create(thr, pc, addr);
|
||||||
s->next = b->head;
|
s->next = b->head;
|
||||||
b->head = s;
|
b->head = s;
|
||||||
|
@ -233,8 +237,17 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) {
|
||||||
BlockDesc *d = getblock(dst);
|
BlockDesc *d = getblock(dst);
|
||||||
BlockDesc *send = getblock(src + size);
|
BlockDesc *send = getblock(src + size);
|
||||||
for (; s != send; s++, d++) {
|
for (; s != send; s++, d++) {
|
||||||
|
CHECK_EQ(d->begin, false);
|
||||||
if (s->begin) {
|
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();
|
s->~BlockDesc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct SyncVar {
|
||||||
static const int kInvalidTid = -1;
|
static const int kInvalidTid = -1;
|
||||||
|
|
||||||
Mutex mtx;
|
Mutex mtx;
|
||||||
const uptr addr;
|
uptr addr;
|
||||||
const u64 uid; // Globally unique id.
|
const u64 uid; // Globally unique id.
|
||||||
SyncClock clock;
|
SyncClock clock;
|
||||||
SyncClock read_clock; // Used for rw mutexes only.
|
SyncClock read_clock; // Used for rw mutexes only.
|
||||||
|
|
Loading…
Reference in New Issue