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