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(%p, %p)\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(%p, %p)\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(%p, %p)\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); 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(%p, %p, %p)\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 DCHECK_NE(size, 0); 126 127 // Assuming it's not running concurrently with threads that do 128 // memory accesses and mutex operations (stop-the-world phase). 129 ctx->metamap.MoveMemory(src, dst, size); 130 131 // Move shadow. 132 u64 *s = (u64*)MemToShadow(src); 133 u64 *d = (u64*)MemToShadow(dst); 134 u64 *send = (u64*)MemToShadow(src + size); 135 uptr inc = 1; 136 if (dst > src) { 137 s = (u64*)MemToShadow(src + size) - 1; 138 d = (u64*)MemToShadow(dst + size) - 1; 139 send = (u64*)MemToShadow(src) - 1; 140 inc = -1; 141 } 142 for (; s != send; s += inc, d += inc) { 143 *d = *s; 144 *s = 0; 145 } 146 } 147 148 jptr __tsan_java_find(jptr *from_ptr, jptr to) { 149 JAVA_FUNC_ENTER(__tsan_java_find); 150 DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); 151 DCHECK_EQ((*from_ptr) % kHeapAlignment, 0); 152 DCHECK_EQ(to % kHeapAlignment, 0); 153 DCHECK_GE(*from_ptr, jctx->heap_begin); 154 DCHECK_LE(to, jctx->heap_begin + jctx->heap_size); 155 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { 156 MBlock *b = ctx->metamap.GetBlock(from); 157 if (b) { 158 *from_ptr = from; 159 return b->siz; 160 } 161 } 162 return 0; 163 } 164 165 void __tsan_java_finalize() { 166 JAVA_FUNC_ENTER(__tsan_java_finalize); 167 DPrintf("#%d: java_finalize()\n", thr->tid); 168 AcquireGlobal(thr); 169 } 170 171 void __tsan_java_mutex_lock(jptr addr) { 172 JAVA_FUNC_ENTER(__tsan_java_mutex_lock); 173 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 174 DCHECK_NE(jctx, 0); 175 DCHECK_GE(addr, jctx->heap_begin); 176 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 177 178 MutexPostLock(thr, 0, addr, 179 MutexFlagLinkerInit | MutexFlagWriteReentrant | 180 MutexFlagDoPreLockOnPostLock); 181 } 182 183 void __tsan_java_mutex_unlock(jptr addr) { 184 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock); 185 DPrintf("#%d: java_mutex_unlock(%p)\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 MutexUnlock(thr, 0, addr); 191 } 192 193 void __tsan_java_mutex_read_lock(jptr addr) { 194 JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock); 195 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 196 DCHECK_NE(jctx, 0); 197 DCHECK_GE(addr, jctx->heap_begin); 198 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 199 200 MutexPostReadLock(thr, 0, addr, 201 MutexFlagLinkerInit | MutexFlagWriteReentrant | 202 MutexFlagDoPreLockOnPostLock); 203 } 204 205 void __tsan_java_mutex_read_unlock(jptr addr) { 206 JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock); 207 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 208 DCHECK_NE(jctx, 0); 209 DCHECK_GE(addr, jctx->heap_begin); 210 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 211 212 MutexReadUnlock(thr, 0, addr); 213 } 214 215 void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 216 JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec); 217 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 218 DCHECK_NE(jctx, 0); 219 DCHECK_GE(addr, jctx->heap_begin); 220 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 221 DCHECK_GT(rec, 0); 222 223 MutexPostLock(thr, 0, addr, 224 MutexFlagLinkerInit | MutexFlagWriteReentrant | 225 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, 226 rec); 227 } 228 229 int __tsan_java_mutex_unlock_rec(jptr addr) { 230 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec); 231 DPrintf("#%d: java_mutex_unlock_rec(%p)\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 return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock); 237 } 238 239 void __tsan_java_acquire(jptr addr) { 240 JAVA_FUNC_ENTER(__tsan_java_acquire); 241 DPrintf("#%d: java_acquire(%p)\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 Acquire(thr, 0, addr); 247 } 248 249 void __tsan_java_release(jptr addr) { 250 JAVA_FUNC_ENTER(__tsan_java_release); 251 DPrintf("#%d: java_release(%p)\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 Release(thr, 0, addr); 257 } 258 259 void __tsan_java_release_store(jptr addr) { 260 JAVA_FUNC_ENTER(__tsan_java_release); 261 DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr); 262 DCHECK_NE(jctx, 0); 263 DCHECK_GE(addr, jctx->heap_begin); 264 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 265 266 ReleaseStore(thr, 0, addr); 267 } 268