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 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; 38 static JavaContext *jctx; 39 40 MBlock *JavaHeapBlock(uptr addr, uptr *start) { 41 if (!jctx || addr < jctx->heap_begin || 42 addr >= jctx->heap_begin + jctx->heap_size) 43 return nullptr; 44 for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin; 45 p -= kMetaShadowCell) { 46 MBlock *b = ctx->metamap.GetBlock(p); 47 if (!b) 48 continue; 49 if (p + b->siz <= addr) 50 return nullptr; 51 *start = p; 52 return b; 53 } 54 return nullptr; 55 } 56 57 } // namespace __tsan 58 59 #define JAVA_FUNC_ENTER(func) \ 60 ThreadState *thr = cur_thread(); \ 61 (void)thr; 62 63 void __tsan_java_init(jptr heap_begin, jptr heap_size) { 64 JAVA_FUNC_ENTER(__tsan_java_init); 65 Initialize(thr); 66 DPrintf("#%d: java_init(0x%zx, 0x%zx)\n", thr->tid, heap_begin, heap_size); 67 DCHECK_EQ(jctx, 0); 68 DCHECK_GT(heap_begin, 0); 69 DCHECK_GT(heap_size, 0); 70 DCHECK_EQ(heap_begin % kHeapAlignment, 0); 71 DCHECK_EQ(heap_size % kHeapAlignment, 0); 72 DCHECK_LT(heap_begin, heap_begin + heap_size); 73 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); 74 } 75 76 int __tsan_java_fini() { 77 JAVA_FUNC_ENTER(__tsan_java_fini); 78 DPrintf("#%d: java_fini()\n", thr->tid); 79 DCHECK_NE(jctx, 0); 80 // FIXME(dvyukov): this does not call atexit() callbacks. 81 int status = Finalize(thr); 82 DPrintf("#%d: java_fini() = %d\n", thr->tid, status); 83 return status; 84 } 85 86 void __tsan_java_alloc(jptr ptr, jptr size) { 87 JAVA_FUNC_ENTER(__tsan_java_alloc); 88 DPrintf("#%d: java_alloc(0x%zx, 0x%zx)\n", thr->tid, ptr, size); 89 DCHECK_NE(jctx, 0); 90 DCHECK_NE(size, 0); 91 DCHECK_EQ(ptr % kHeapAlignment, 0); 92 DCHECK_EQ(size % kHeapAlignment, 0); 93 DCHECK_GE(ptr, jctx->heap_begin); 94 DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 95 96 OnUserAlloc(thr, 0, ptr, size, false); 97 } 98 99 void __tsan_java_free(jptr ptr, jptr size) { 100 JAVA_FUNC_ENTER(__tsan_java_free); 101 DPrintf("#%d: java_free(0x%zx, 0x%zx)\n", thr->tid, ptr, size); 102 DCHECK_NE(jctx, 0); 103 DCHECK_NE(size, 0); 104 DCHECK_EQ(ptr % kHeapAlignment, 0); 105 DCHECK_EQ(size % kHeapAlignment, 0); 106 DCHECK_GE(ptr, jctx->heap_begin); 107 DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 108 109 ctx->metamap.FreeRange(thr->proc(), ptr, size, false); 110 } 111 112 void __tsan_java_move(jptr src, jptr dst, jptr size) { 113 JAVA_FUNC_ENTER(__tsan_java_move); 114 DPrintf("#%d: java_move(0x%zx, 0x%zx, 0x%zx)\n", thr->tid, src, dst, size); 115 DCHECK_NE(jctx, 0); 116 DCHECK_NE(size, 0); 117 DCHECK_EQ(src % kHeapAlignment, 0); 118 DCHECK_EQ(dst % kHeapAlignment, 0); 119 DCHECK_EQ(size % kHeapAlignment, 0); 120 DCHECK_GE(src, jctx->heap_begin); 121 DCHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 122 DCHECK_GE(dst, jctx->heap_begin); 123 DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 124 DCHECK_NE(dst, src); 125 126 // Assuming it's not running concurrently with threads that do 127 // memory accesses and mutex operations (stop-the-world phase). 128 ctx->metamap.MoveMemory(src, dst, size); 129 130 // Clear the destination shadow range. 131 // We used to move shadow from src to dst, but the trace format does not 132 // support that anymore as it contains addresses of accesses. 133 RawShadow *d = MemToShadow(dst); 134 RawShadow *dend = MemToShadow(dst + size); 135 ShadowSet(d, dend, Shadow::kEmpty); 136 } 137 138 jptr __tsan_java_find(jptr *from_ptr, jptr to) { 139 JAVA_FUNC_ENTER(__tsan_java_find); 140 DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to); 141 DCHECK_EQ((*from_ptr) % kHeapAlignment, 0); 142 DCHECK_EQ(to % kHeapAlignment, 0); 143 DCHECK_GE(*from_ptr, jctx->heap_begin); 144 DCHECK_LE(to, jctx->heap_begin + jctx->heap_size); 145 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { 146 MBlock *b = ctx->metamap.GetBlock(from); 147 if (b) { 148 *from_ptr = from; 149 return b->siz; 150 } 151 } 152 return 0; 153 } 154 155 void __tsan_java_finalize() { 156 JAVA_FUNC_ENTER(__tsan_java_finalize); 157 DPrintf("#%d: java_finalize()\n", thr->tid); 158 AcquireGlobal(thr); 159 } 160 161 void __tsan_java_mutex_lock(jptr addr) { 162 JAVA_FUNC_ENTER(__tsan_java_mutex_lock); 163 DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr); 164 DCHECK_NE(jctx, 0); 165 DCHECK_GE(addr, jctx->heap_begin); 166 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 167 168 MutexPostLock(thr, 0, addr, 169 MutexFlagLinkerInit | MutexFlagWriteReentrant | 170 MutexFlagDoPreLockOnPostLock); 171 } 172 173 void __tsan_java_mutex_unlock(jptr addr) { 174 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock); 175 DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr); 176 DCHECK_NE(jctx, 0); 177 DCHECK_GE(addr, jctx->heap_begin); 178 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 179 180 MutexUnlock(thr, 0, addr); 181 } 182 183 void __tsan_java_mutex_read_lock(jptr addr) { 184 JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock); 185 DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr); 186 DCHECK_NE(jctx, 0); 187 DCHECK_GE(addr, jctx->heap_begin); 188 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 189 190 MutexPostReadLock(thr, 0, addr, 191 MutexFlagLinkerInit | MutexFlagWriteReentrant | 192 MutexFlagDoPreLockOnPostLock); 193 } 194 195 void __tsan_java_mutex_read_unlock(jptr addr) { 196 JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock); 197 DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr); 198 DCHECK_NE(jctx, 0); 199 DCHECK_GE(addr, jctx->heap_begin); 200 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 201 202 MutexReadUnlock(thr, 0, addr); 203 } 204 205 void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 206 JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec); 207 DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec); 208 DCHECK_NE(jctx, 0); 209 DCHECK_GE(addr, jctx->heap_begin); 210 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 211 DCHECK_GT(rec, 0); 212 213 MutexPostLock(thr, 0, addr, 214 MutexFlagLinkerInit | MutexFlagWriteReentrant | 215 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, 216 rec); 217 } 218 219 int __tsan_java_mutex_unlock_rec(jptr addr) { 220 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec); 221 DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr); 222 DCHECK_NE(jctx, 0); 223 DCHECK_GE(addr, jctx->heap_begin); 224 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 225 226 return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock); 227 } 228 229 void __tsan_java_acquire(jptr addr) { 230 JAVA_FUNC_ENTER(__tsan_java_acquire); 231 DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr); 232 DCHECK_NE(jctx, 0); 233 DCHECK_GE(addr, jctx->heap_begin); 234 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 235 236 Acquire(thr, 0, addr); 237 } 238 239 void __tsan_java_release(jptr addr) { 240 JAVA_FUNC_ENTER(__tsan_java_release); 241 DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr); 242 DCHECK_NE(jctx, 0); 243 DCHECK_GE(addr, jctx->heap_begin); 244 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 245 246 Release(thr, 0, addr); 247 } 248 249 void __tsan_java_release_store(jptr addr) { 250 JAVA_FUNC_ENTER(__tsan_java_release); 251 DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr); 252 DCHECK_NE(jctx, 0); 253 DCHECK_GE(addr, jctx->heap_begin); 254 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 255 256 ReleaseStore(thr, 0, addr); 257 } 258