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