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 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); 66 CHECK_EQ(jctx, 0); 67 CHECK_GT(heap_begin, 0); 68 CHECK_GT(heap_size, 0); 69 CHECK_EQ(heap_begin % kHeapAlignment, 0); 70 CHECK_EQ(heap_size % kHeapAlignment, 0); 71 CHECK_LT(heap_begin, heap_begin + heap_size); 72 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); 73 } 74 75 int __tsan_java_fini() { 76 JAVA_FUNC_ENTER(__tsan_java_fini); 77 DPrintf("#%d: java_fini()\n", thr->tid); 78 CHECK_NE(jctx, 0); 79 // FIXME(dvyukov): this does not call atexit() callbacks. 80 int status = Finalize(thr); 81 DPrintf("#%d: java_fini() = %d\n", thr->tid, status); 82 return status; 83 } 84 85 void __tsan_java_alloc(jptr ptr, jptr size) { 86 JAVA_FUNC_ENTER(__tsan_java_alloc); 87 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); 88 CHECK_NE(jctx, 0); 89 CHECK_NE(size, 0); 90 CHECK_EQ(ptr % kHeapAlignment, 0); 91 CHECK_EQ(size % kHeapAlignment, 0); 92 CHECK_GE(ptr, jctx->heap_begin); 93 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 94 95 OnUserAlloc(thr, 0, ptr, size, false); 96 } 97 98 void __tsan_java_free(jptr ptr, jptr size) { 99 JAVA_FUNC_ENTER(__tsan_java_free); 100 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); 101 CHECK_NE(jctx, 0); 102 CHECK_NE(size, 0); 103 CHECK_EQ(ptr % kHeapAlignment, 0); 104 CHECK_EQ(size % kHeapAlignment, 0); 105 CHECK_GE(ptr, jctx->heap_begin); 106 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 107 108 ctx->metamap.FreeRange(thr->proc(), ptr, size); 109 } 110 111 void __tsan_java_move(jptr src, jptr dst, jptr size) { 112 JAVA_FUNC_ENTER(__tsan_java_move); 113 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); 114 CHECK_NE(jctx, 0); 115 CHECK_NE(size, 0); 116 CHECK_EQ(src % kHeapAlignment, 0); 117 CHECK_EQ(dst % kHeapAlignment, 0); 118 CHECK_EQ(size % kHeapAlignment, 0); 119 CHECK_GE(src, jctx->heap_begin); 120 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 121 CHECK_GE(dst, jctx->heap_begin); 122 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 123 CHECK_NE(dst, src); 124 CHECK_NE(size, 0); 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 // Move shadow. 131 u64 *s = (u64*)MemToShadow(src); 132 u64 *d = (u64*)MemToShadow(dst); 133 u64 *send = (u64*)MemToShadow(src + size); 134 uptr inc = 1; 135 if (dst > src) { 136 s = (u64*)MemToShadow(src + size) - 1; 137 d = (u64*)MemToShadow(dst + size) - 1; 138 send = (u64*)MemToShadow(src) - 1; 139 inc = -1; 140 } 141 for (; s != send; s += inc, d += inc) { 142 *d = *s; 143 *s = 0; 144 } 145 } 146 147 jptr __tsan_java_find(jptr *from_ptr, jptr to) { 148 JAVA_FUNC_ENTER(__tsan_java_find); 149 DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); 150 CHECK_EQ((*from_ptr) % kHeapAlignment, 0); 151 CHECK_EQ(to % kHeapAlignment, 0); 152 CHECK_GE(*from_ptr, jctx->heap_begin); 153 CHECK_LE(to, jctx->heap_begin + jctx->heap_size); 154 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { 155 MBlock *b = ctx->metamap.GetBlock(from); 156 if (b) { 157 *from_ptr = from; 158 return b->siz; 159 } 160 } 161 return 0; 162 } 163 164 void __tsan_java_finalize() { 165 JAVA_FUNC_ENTER(__tsan_java_finalize); 166 DPrintf("#%d: java_mutex_finalize()\n", thr->tid); 167 AcquireGlobal(thr); 168 } 169 170 void __tsan_java_mutex_lock(jptr addr) { 171 JAVA_FUNC_ENTER(__tsan_java_mutex_lock); 172 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 173 CHECK_NE(jctx, 0); 174 CHECK_GE(addr, jctx->heap_begin); 175 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 176 177 MutexPostLock(thr, 0, addr, 178 MutexFlagLinkerInit | MutexFlagWriteReentrant | 179 MutexFlagDoPreLockOnPostLock); 180 } 181 182 void __tsan_java_mutex_unlock(jptr addr) { 183 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock); 184 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); 185 CHECK_NE(jctx, 0); 186 CHECK_GE(addr, jctx->heap_begin); 187 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 188 189 MutexUnlock(thr, 0, addr); 190 } 191 192 void __tsan_java_mutex_read_lock(jptr addr) { 193 JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock); 194 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 195 CHECK_NE(jctx, 0); 196 CHECK_GE(addr, jctx->heap_begin); 197 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 198 199 MutexPostReadLock(thr, 0, addr, 200 MutexFlagLinkerInit | MutexFlagWriteReentrant | 201 MutexFlagDoPreLockOnPostLock); 202 } 203 204 void __tsan_java_mutex_read_unlock(jptr addr) { 205 JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock); 206 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 207 CHECK_NE(jctx, 0); 208 CHECK_GE(addr, jctx->heap_begin); 209 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 210 211 MutexReadUnlock(thr, 0, addr); 212 } 213 214 void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 215 JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec); 216 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 217 CHECK_NE(jctx, 0); 218 CHECK_GE(addr, jctx->heap_begin); 219 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 220 CHECK_GT(rec, 0); 221 222 MutexPostLock(thr, 0, addr, 223 MutexFlagLinkerInit | MutexFlagWriteReentrant | 224 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, 225 rec); 226 } 227 228 int __tsan_java_mutex_unlock_rec(jptr addr) { 229 JAVA_FUNC_ENTER(__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, 0, addr, MutexFlagRecursiveUnlock); 236 } 237 238 void __tsan_java_acquire(jptr addr) { 239 JAVA_FUNC_ENTER(__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, 0, addr); 246 } 247 248 void __tsan_java_release(jptr addr) { 249 JAVA_FUNC_ENTER(__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, 0, addr); 256 } 257 258 void __tsan_java_release_store(jptr addr) { 259 JAVA_FUNC_ENTER(__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, 0, addr); 266 } 267