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 SCOPED_JAVA_FUNC(func) \ 60 ThreadState *thr = cur_thread(); \ 61 (void)thr; \ 62 /**/ 63 64 void __tsan_java_init(jptr heap_begin, jptr heap_size) { 65 SCOPED_JAVA_FUNC(__tsan_java_init); 66 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); 67 CHECK_EQ(jctx, 0); 68 CHECK_GT(heap_begin, 0); 69 CHECK_GT(heap_size, 0); 70 CHECK_EQ(heap_begin % kHeapAlignment, 0); 71 CHECK_EQ(heap_size % kHeapAlignment, 0); 72 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_fini); 78 DPrintf("#%d: java_fini()\n", thr->tid); 79 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_alloc); 88 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); 89 CHECK_NE(jctx, 0); 90 CHECK_NE(size, 0); 91 CHECK_EQ(ptr % kHeapAlignment, 0); 92 CHECK_EQ(size % kHeapAlignment, 0); 93 CHECK_GE(ptr, jctx->heap_begin); 94 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_free); 101 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); 102 CHECK_NE(jctx, 0); 103 CHECK_NE(size, 0); 104 CHECK_EQ(ptr % kHeapAlignment, 0); 105 CHECK_EQ(size % kHeapAlignment, 0); 106 CHECK_GE(ptr, jctx->heap_begin); 107 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_move); 114 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); 115 CHECK_NE(jctx, 0); 116 CHECK_NE(size, 0); 117 CHECK_EQ(src % kHeapAlignment, 0); 118 CHECK_EQ(dst % kHeapAlignment, 0); 119 CHECK_EQ(size % kHeapAlignment, 0); 120 CHECK_GE(src, jctx->heap_begin); 121 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 122 CHECK_GE(dst, jctx->heap_begin); 123 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 124 CHECK_NE(dst, src); 125 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_find); 150 DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); 151 CHECK_EQ((*from_ptr) % kHeapAlignment, 0); 152 CHECK_EQ(to % kHeapAlignment, 0); 153 CHECK_GE(*from_ptr, jctx->heap_begin); 154 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_finalize); 167 DPrintf("#%d: java_mutex_finalize()\n", thr->tid); 168 AcquireGlobal(thr); 169 } 170 171 void __tsan_java_mutex_lock(jptr addr) { 172 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock); 173 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 174 CHECK_NE(jctx, 0); 175 CHECK_GE(addr, jctx->heap_begin); 176 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock); 185 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); 186 CHECK_NE(jctx, 0); 187 CHECK_GE(addr, jctx->heap_begin); 188 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock); 195 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 196 CHECK_NE(jctx, 0); 197 CHECK_GE(addr, jctx->heap_begin); 198 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock); 207 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 208 CHECK_NE(jctx, 0); 209 CHECK_GE(addr, jctx->heap_begin); 210 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); 217 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 218 CHECK_NE(jctx, 0); 219 CHECK_GE(addr, jctx->heap_begin); 220 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 221 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec); 231 DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr); 232 CHECK_NE(jctx, 0); 233 CHECK_GE(addr, jctx->heap_begin); 234 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_acquire); 241 DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr); 242 CHECK_NE(jctx, 0); 243 CHECK_GE(addr, jctx->heap_begin); 244 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 245 246 Acquire(thr, 0, addr); 247 } 248 249 void __tsan_java_release(jptr addr) { 250 SCOPED_JAVA_FUNC(__tsan_java_release); 251 DPrintf("#%d: java_release(%p)\n", thr->tid, addr); 252 CHECK_NE(jctx, 0); 253 CHECK_GE(addr, jctx->heap_begin); 254 CHECK_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 SCOPED_JAVA_FUNC(__tsan_java_release); 261 DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr); 262 CHECK_NE(jctx, 0); 263 CHECK_GE(addr, jctx->heap_begin); 264 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 265 266 ReleaseStore(thr, 0, addr); 267 } 268