| 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(p: addr, align: 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, pc: 0, p: ptr, sz: size, write: 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(proc: thr->proc(), p: ptr, sz: size, reset: 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, sz: 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(x: dst); |
| 134 | RawShadow *dend = MemToShadow(x: dst + size); |
| 135 | ShadowSet(p: d, end: dend, v: 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(p: 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, pc: 0, addr, |
| 169 | flagz: 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, pc: 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, pc: 0, addr, |
| 191 | flagz: 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, pc: 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, pc: 0, addr, |
| 214 | flagz: 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, pc: 0, addr, flagz: 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, pc: 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, pc: 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, pc: 0, addr); |
| 257 | } |
| 258 | |