tsan_interface_java.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
1//===-- tsan_interface_java.cc --------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of ThreadSanitizer (TSan), a race detector. 11// 12//===----------------------------------------------------------------------===// 13 14#include "tsan_interface_java.h" 15#include "tsan_rtl.h" 16#include "tsan_mutex.h" 17#include "sanitizer_common/sanitizer_internal_defs.h" 18#include "sanitizer_common/sanitizer_common.h" 19#include "sanitizer_common/sanitizer_placement_new.h" 20#include "sanitizer_common/sanitizer_stacktrace.h" 21#include "sanitizer_common/sanitizer_procmaps.h" 22 23using namespace __tsan; // NOLINT 24 25namespace __tsan { 26 27const uptr kHeapShadow = 0x300000000000ull; 28const uptr kHeapAlignment = 8; 29 30struct BlockDesc { 31 bool begin; 32 Mutex mtx; 33 SyncVar *head; 34 35 BlockDesc() 36 : mtx(MutexTypeJavaMBlock, StatMtxJavaMBlock) 37 , head() { 38 CHECK_EQ(begin, false); 39 begin = true; 40 } 41 42 ~BlockDesc() { 43 CHECK_EQ(begin, true); 44 begin = false; 45 ThreadState *thr = cur_thread(); 46 SyncVar *s = head; 47 while (s) { 48 SyncVar *s1 = s->next; 49 StatInc(thr, StatSyncDestroyed); 50 s->mtx.Lock(); 51 s->mtx.Unlock(); 52 thr->mset.Remove(s->GetId()); 53 DestroyAndFree(s); 54 s = s1; 55 } 56 } 57}; 58 59struct JavaContext { 60 const uptr heap_begin; 61 const uptr heap_size; 62 BlockDesc *heap_shadow; 63 64 JavaContext(jptr heap_begin, jptr heap_size) 65 : heap_begin(heap_begin) 66 , heap_size(heap_size) { 67 uptr size = heap_size / kHeapAlignment * sizeof(BlockDesc); 68 heap_shadow = (BlockDesc*)MmapFixedNoReserve(kHeapShadow, size); 69 if ((uptr)heap_shadow != kHeapShadow) { 70 Printf("ThreadSanitizer: failed to mmap Java heap shadow\n"); 71 Die(); 72 } 73 } 74}; 75 76class ScopedJavaFunc { 77 public: 78 ScopedJavaFunc(ThreadState *thr, uptr pc) 79 : thr_(thr) { 80 Initialize(thr_); 81 FuncEntry(thr, pc); 82 } 83 84 ~ScopedJavaFunc() { 85 FuncExit(thr_); 86 // FIXME(dvyukov): process pending signals. 87 } 88 89 private: 90 ThreadState *thr_; 91}; 92 93static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; 94static JavaContext *jctx; 95 96static BlockDesc *getblock(uptr addr) { 97 uptr i = (addr - jctx->heap_begin) / kHeapAlignment; 98 return &jctx->heap_shadow[i]; 99} 100 101static uptr USED getmem(BlockDesc *b) { 102 uptr i = b - jctx->heap_shadow; 103 uptr p = jctx->heap_begin + i * kHeapAlignment; 104 CHECK_GE(p, jctx->heap_begin); 105 CHECK_LT(p, jctx->heap_begin + jctx->heap_size); 106 return p; 107} 108 109static BlockDesc *getblockbegin(uptr addr) { 110 for (BlockDesc *b = getblock(addr);; b--) { 111 CHECK_GE(b, jctx->heap_shadow); 112 if (b->begin) 113 return b; 114 } 115 return 0; 116} 117 118SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr, 119 bool write_lock, bool create) { 120 if (jctx == 0 || addr < jctx->heap_begin 121 || addr >= jctx->heap_begin + jctx->heap_size) 122 return 0; 123 BlockDesc *b = getblockbegin(addr); 124 DPrintf("#%d: GetJavaSync %p->%p\n", thr->tid, addr, b); 125 Lock l(&b->mtx); 126 SyncVar *s = b->head; 127 for (; s; s = s->next) { 128 if (s->addr == addr) { 129 DPrintf("#%d: found existing sync for %p\n", thr->tid, addr); 130 break; 131 } 132 } 133 if (s == 0 && create) { 134 DPrintf("#%d: creating new sync for %p\n", thr->tid, addr); 135 s = ctx->synctab.Create(thr, pc, addr); 136 s->next = b->head; 137 b->head = s; 138 } 139 if (s) { 140 if (write_lock) 141 s->mtx.Lock(); 142 else 143 s->mtx.ReadLock(); 144 } 145 return s; 146} 147 148SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) { 149 // We do not destroy Java mutexes other than in __tsan_java_free(). 150 return 0; 151} 152 153} // namespace __tsan 154 155#define SCOPED_JAVA_FUNC(func) \ 156 ThreadState *thr = cur_thread(); \ 157 const uptr caller_pc = GET_CALLER_PC(); \ 158 const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \ 159 (void)pc; \ 160 ScopedJavaFunc scoped(thr, caller_pc); \ 161/**/ 162 163void __tsan_java_init(jptr heap_begin, jptr heap_size) { 164 SCOPED_JAVA_FUNC(__tsan_java_init); 165 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); 166 CHECK_EQ(jctx, 0); 167 CHECK_GT(heap_begin, 0); 168 CHECK_GT(heap_size, 0); 169 CHECK_EQ(heap_begin % kHeapAlignment, 0); 170 CHECK_EQ(heap_size % kHeapAlignment, 0); 171 CHECK_LT(heap_begin, heap_begin + heap_size); 172 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); 173} 174 175int __tsan_java_fini() { 176 SCOPED_JAVA_FUNC(__tsan_java_fini); 177 DPrintf("#%d: java_fini()\n", thr->tid); 178 CHECK_NE(jctx, 0); 179 // FIXME(dvyukov): this does not call atexit() callbacks. 180 int status = Finalize(thr); 181 DPrintf("#%d: java_fini() = %d\n", thr->tid, status); 182 return status; 183} 184 185void __tsan_java_alloc(jptr ptr, jptr size) { 186 SCOPED_JAVA_FUNC(__tsan_java_alloc); 187 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); 188 CHECK_NE(jctx, 0); 189 CHECK_NE(size, 0); 190 CHECK_EQ(ptr % kHeapAlignment, 0); 191 CHECK_EQ(size % kHeapAlignment, 0); 192 CHECK_GE(ptr, jctx->heap_begin); 193 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 194 195 BlockDesc *b = getblock(ptr); 196 new(b) BlockDesc(); 197} 198 199void __tsan_java_free(jptr ptr, jptr size) { 200 SCOPED_JAVA_FUNC(__tsan_java_free); 201 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); 202 CHECK_NE(jctx, 0); 203 CHECK_NE(size, 0); 204 CHECK_EQ(ptr % kHeapAlignment, 0); 205 CHECK_EQ(size % kHeapAlignment, 0); 206 CHECK_GE(ptr, jctx->heap_begin); 207 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 208 209 BlockDesc *beg = getblock(ptr); 210 BlockDesc *end = getblock(ptr + size); 211 for (BlockDesc *b = beg; b != end; b++) { 212 if (b->begin) 213 b->~BlockDesc(); 214 } 215} 216 217void __tsan_java_move(jptr src, jptr dst, jptr size) { 218 SCOPED_JAVA_FUNC(__tsan_java_move); 219 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); 220 CHECK_NE(jctx, 0); 221 CHECK_NE(size, 0); 222 CHECK_EQ(src % kHeapAlignment, 0); 223 CHECK_EQ(dst % kHeapAlignment, 0); 224 CHECK_EQ(size % kHeapAlignment, 0); 225 CHECK_GE(src, jctx->heap_begin); 226 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 227 CHECK_GE(dst, jctx->heap_begin); 228 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 229 CHECK(dst >= src + size || src >= dst + size); 230 231 // Assuming it's not running concurrently with threads that do 232 // memory accesses and mutex operations (stop-the-world phase). 233 { // NOLINT 234 BlockDesc *s = getblock(src); 235 BlockDesc *d = getblock(dst); 236 BlockDesc *send = getblock(src + size); 237 for (; s != send; s++, d++) { 238 CHECK_EQ(d->begin, false); 239 if (s->begin) { 240 DPrintf("#%d: moving block %p->%p\n", thr->tid, getmem(s), getmem(d)); 241 new(d) BlockDesc; 242 d->head = s->head; 243 for (SyncVar *sync = d->head; sync; sync = sync->next) { 244 uptr newaddr = sync->addr - src + dst; 245 DPrintf("#%d: moving sync %p->%p\n", thr->tid, sync->addr, newaddr); 246 sync->addr = newaddr; 247 } 248 s->head = 0; 249 s->~BlockDesc(); 250 } 251 } 252 } 253 254 { // NOLINT 255 u64 *s = (u64*)MemToShadow(src); 256 u64 *d = (u64*)MemToShadow(dst); 257 u64 *send = (u64*)MemToShadow(src + size); 258 for (; s != send; s++, d++) { 259 *d = *s; 260 *s = 0; 261 } 262 } 263} 264 265void __tsan_java_mutex_lock(jptr addr) { 266 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock); 267 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 268 CHECK_NE(jctx, 0); 269 CHECK_GE(addr, jctx->heap_begin); 270 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 271 272 MutexCreate(thr, pc, addr, true, true, true); 273 MutexLock(thr, pc, addr); 274} 275 276void __tsan_java_mutex_unlock(jptr addr) { 277 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock); 278 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); 279 CHECK_NE(jctx, 0); 280 CHECK_GE(addr, jctx->heap_begin); 281 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 282 283 MutexUnlock(thr, pc, addr); 284} 285 286void __tsan_java_mutex_read_lock(jptr addr) { 287 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock); 288 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 289 CHECK_NE(jctx, 0); 290 CHECK_GE(addr, jctx->heap_begin); 291 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 292 293 MutexCreate(thr, pc, addr, true, true, true); 294 MutexReadLock(thr, pc, addr); 295} 296 297void __tsan_java_mutex_read_unlock(jptr addr) { 298 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock); 299 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 300 CHECK_NE(jctx, 0); 301 CHECK_GE(addr, jctx->heap_begin); 302 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 303 304 MutexReadUnlock(thr, pc, addr); 305} 306 307void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 308 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); 309 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 310 CHECK_NE(jctx, 0); 311 CHECK_GE(addr, jctx->heap_begin); 312 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 313 CHECK_GT(rec, 0); 314 315 MutexCreate(thr, pc, addr, true, true, true); 316 MutexLock(thr, pc, addr, rec); 317} 318 319int __tsan_java_mutex_unlock_rec(jptr addr) { 320 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec); 321 DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr); 322 CHECK_NE(jctx, 0); 323 CHECK_GE(addr, jctx->heap_begin); 324 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 325 326 return MutexUnlock(thr, pc, addr, true); 327} 328