1 //===-- tsan_interface_java.cpp -------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of ThreadSanitizer (TSan), a race detector. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "tsan_interface_java.h" 14 #include "tsan_rtl.h" 15 #include "sanitizer_common/sanitizer_internal_defs.h" 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "sanitizer_common/sanitizer_placement_new.h" 18 #include "sanitizer_common/sanitizer_stacktrace.h" 19 #include "sanitizer_common/sanitizer_procmaps.h" 20 21 using namespace __tsan; 22 23 const jptr kHeapAlignment = 8; 24 25 namespace __tsan { 26 27 struct JavaContext { 28 const uptr heap_begin; 29 const uptr heap_size; 30 31 JavaContext(jptr heap_begin, jptr heap_size) 32 : heap_begin(heap_begin) 33 , heap_size(heap_size) { 34 } 35 }; 36 37 class ScopedJavaFunc { 38 public: 39 ScopedJavaFunc(ThreadState *thr, uptr pc) 40 : thr_(thr) { 41 Initialize(thr_); 42 FuncEntry(thr, pc); 43 } 44 45 ~ScopedJavaFunc() { 46 FuncExit(thr_); 47 // FIXME(dvyukov): process pending signals. 48 } 49 50 private: 51 ThreadState *thr_; 52 }; 53 54 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; 55 static JavaContext *jctx; 56 57 MBlock *JavaHeapBlock(uptr addr, uptr *start) { 58 if (!jctx || addr < jctx->heap_begin || 59 addr >= jctx->heap_begin + jctx->heap_size) 60 return nullptr; 61 for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin; 62 p -= kMetaShadowCell) { 63 MBlock *b = ctx->metamap.GetBlock(p); 64 if (!b) 65 continue; 66 if (p + b->siz <= addr) 67 return nullptr; 68 *start = p; 69 return b; 70 } 71 return nullptr; 72 } 73 74 } // namespace __tsan 75 76 #define SCOPED_JAVA_FUNC(func) \ 77 ThreadState *thr = cur_thread(); \ 78 const uptr caller_pc = GET_CALLER_PC(); \ 79 const uptr pc = StackTrace::GetCurrentPc(); \ 80 (void)pc; \ 81 ScopedJavaFunc scoped(thr, caller_pc); \ 82 /**/ 83 84 void __tsan_java_init(jptr heap_begin, jptr heap_size) { 85 SCOPED_JAVA_FUNC(__tsan_java_init); 86 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); 87 CHECK_EQ(jctx, 0); 88 CHECK_GT(heap_begin, 0); 89 CHECK_GT(heap_size, 0); 90 CHECK_EQ(heap_begin % kHeapAlignment, 0); 91 CHECK_EQ(heap_size % kHeapAlignment, 0); 92 CHECK_LT(heap_begin, heap_begin + heap_size); 93 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); 94 } 95 96 int __tsan_java_fini() { 97 SCOPED_JAVA_FUNC(__tsan_java_fini); 98 DPrintf("#%d: java_fini()\n", thr->tid); 99 CHECK_NE(jctx, 0); 100 // FIXME(dvyukov): this does not call atexit() callbacks. 101 int status = Finalize(thr); 102 DPrintf("#%d: java_fini() = %d\n", thr->tid, status); 103 return status; 104 } 105 106 void __tsan_java_alloc(jptr ptr, jptr size) { 107 SCOPED_JAVA_FUNC(__tsan_java_alloc); 108 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); 109 CHECK_NE(jctx, 0); 110 CHECK_NE(size, 0); 111 CHECK_EQ(ptr % kHeapAlignment, 0); 112 CHECK_EQ(size % kHeapAlignment, 0); 113 CHECK_GE(ptr, jctx->heap_begin); 114 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 115 116 OnUserAlloc(thr, pc, ptr, size, false); 117 } 118 119 void __tsan_java_free(jptr ptr, jptr size) { 120 SCOPED_JAVA_FUNC(__tsan_java_free); 121 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); 122 CHECK_NE(jctx, 0); 123 CHECK_NE(size, 0); 124 CHECK_EQ(ptr % kHeapAlignment, 0); 125 CHECK_EQ(size % kHeapAlignment, 0); 126 CHECK_GE(ptr, jctx->heap_begin); 127 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 128 129 ctx->metamap.FreeRange(thr->proc(), ptr, size); 130 } 131 132 void __tsan_java_move(jptr src, jptr dst, jptr size) { 133 SCOPED_JAVA_FUNC(__tsan_java_move); 134 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); 135 CHECK_NE(jctx, 0); 136 CHECK_NE(size, 0); 137 CHECK_EQ(src % kHeapAlignment, 0); 138 CHECK_EQ(dst % kHeapAlignment, 0); 139 CHECK_EQ(size % kHeapAlignment, 0); 140 CHECK_GE(src, jctx->heap_begin); 141 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 142 CHECK_GE(dst, jctx->heap_begin); 143 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 144 CHECK_NE(dst, src); 145 CHECK_NE(size, 0); 146 147 // Assuming it's not running concurrently with threads that do 148 // memory accesses and mutex operations (stop-the-world phase). 149 ctx->metamap.MoveMemory(src, dst, size); 150 151 // Move shadow. 152 u64 *s = (u64*)MemToShadow(src); 153 u64 *d = (u64*)MemToShadow(dst); 154 u64 *send = (u64*)MemToShadow(src + size); 155 uptr inc = 1; 156 if (dst > src) { 157 s = (u64*)MemToShadow(src + size) - 1; 158 d = (u64*)MemToShadow(dst + size) - 1; 159 send = (u64*)MemToShadow(src) - 1; 160 inc = -1; 161 } 162 for (; s != send; s += inc, d += inc) { 163 *d = *s; 164 *s = 0; 165 } 166 } 167 168 jptr __tsan_java_find(jptr *from_ptr, jptr to) { 169 SCOPED_JAVA_FUNC(__tsan_java_find); 170 DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); 171 CHECK_EQ((*from_ptr) % kHeapAlignment, 0); 172 CHECK_EQ(to % kHeapAlignment, 0); 173 CHECK_GE(*from_ptr, jctx->heap_begin); 174 CHECK_LE(to, jctx->heap_begin + jctx->heap_size); 175 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { 176 MBlock *b = ctx->metamap.GetBlock(from); 177 if (b) { 178 *from_ptr = from; 179 return b->siz; 180 } 181 } 182 return 0; 183 } 184 185 void __tsan_java_finalize() { 186 SCOPED_JAVA_FUNC(__tsan_java_finalize); 187 DPrintf("#%d: java_mutex_finalize()\n", thr->tid); 188 AcquireGlobal(thr); 189 } 190 191 void __tsan_java_mutex_lock(jptr addr) { 192 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock); 193 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 194 CHECK_NE(jctx, 0); 195 CHECK_GE(addr, jctx->heap_begin); 196 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 197 198 MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | 199 MutexFlagDoPreLockOnPostLock); 200 } 201 202 void __tsan_java_mutex_unlock(jptr addr) { 203 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock); 204 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); 205 CHECK_NE(jctx, 0); 206 CHECK_GE(addr, jctx->heap_begin); 207 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 208 209 MutexUnlock(thr, pc, addr); 210 } 211 212 void __tsan_java_mutex_read_lock(jptr addr) { 213 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock); 214 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 215 CHECK_NE(jctx, 0); 216 CHECK_GE(addr, jctx->heap_begin); 217 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 218 219 MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit | 220 MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock); 221 } 222 223 void __tsan_java_mutex_read_unlock(jptr addr) { 224 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock); 225 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 226 CHECK_NE(jctx, 0); 227 CHECK_GE(addr, jctx->heap_begin); 228 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 229 230 MutexReadUnlock(thr, pc, addr); 231 } 232 233 void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 234 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); 235 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 236 CHECK_NE(jctx, 0); 237 CHECK_GE(addr, jctx->heap_begin); 238 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 239 CHECK_GT(rec, 0); 240 241 MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | 242 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec); 243 } 244 245 int __tsan_java_mutex_unlock_rec(jptr addr) { 246 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec); 247 DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr); 248 CHECK_NE(jctx, 0); 249 CHECK_GE(addr, jctx->heap_begin); 250 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 251 252 return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock); 253 } 254 255 void __tsan_java_acquire(jptr addr) { 256 SCOPED_JAVA_FUNC(__tsan_java_acquire); 257 DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr); 258 CHECK_NE(jctx, 0); 259 CHECK_GE(addr, jctx->heap_begin); 260 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 261 262 Acquire(thr, caller_pc, addr); 263 } 264 265 void __tsan_java_release(jptr addr) { 266 SCOPED_JAVA_FUNC(__tsan_java_release); 267 DPrintf("#%d: java_release(%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 Release(thr, caller_pc, addr); 273 } 274 275 void __tsan_java_release_store(jptr addr) { 276 SCOPED_JAVA_FUNC(__tsan_java_release); 277 DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr); 278 CHECK_NE(jctx, 0); 279 CHECK_GE(addr, jctx->heap_begin); 280 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 281 282 ReleaseStore(thr, caller_pc, addr); 283 } 284