tsan_interface_java.cpp revision 1.1
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 "tsan_mutex.h" 16#include "sanitizer_common/sanitizer_internal_defs.h" 17#include "sanitizer_common/sanitizer_common.h" 18#include "sanitizer_common/sanitizer_placement_new.h" 19#include "sanitizer_common/sanitizer_stacktrace.h" 20#include "sanitizer_common/sanitizer_procmaps.h" 21 22using namespace __tsan; 23 24const jptr kHeapAlignment = 8; 25 26namespace __tsan { 27 28struct JavaContext { 29 const uptr heap_begin; 30 const uptr heap_size; 31 32 JavaContext(jptr heap_begin, jptr heap_size) 33 : heap_begin(heap_begin) 34 , heap_size(heap_size) { 35 } 36}; 37 38class ScopedJavaFunc { 39 public: 40 ScopedJavaFunc(ThreadState *thr, uptr pc) 41 : thr_(thr) { 42 Initialize(thr_); 43 FuncEntry(thr, pc); 44 } 45 46 ~ScopedJavaFunc() { 47 FuncExit(thr_); 48 // FIXME(dvyukov): process pending signals. 49 } 50 51 private: 52 ThreadState *thr_; 53}; 54 55static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; 56static JavaContext *jctx; 57 58} // namespace __tsan 59 60#define SCOPED_JAVA_FUNC(func) \ 61 ThreadState *thr = cur_thread(); \ 62 const uptr caller_pc = GET_CALLER_PC(); \ 63 const uptr pc = StackTrace::GetCurrentPc(); \ 64 (void)pc; \ 65 ScopedJavaFunc scoped(thr, caller_pc); \ 66/**/ 67 68void __tsan_java_init(jptr heap_begin, jptr heap_size) { 69 SCOPED_JAVA_FUNC(__tsan_java_init); 70 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); 71 CHECK_EQ(jctx, 0); 72 CHECK_GT(heap_begin, 0); 73 CHECK_GT(heap_size, 0); 74 CHECK_EQ(heap_begin % kHeapAlignment, 0); 75 CHECK_EQ(heap_size % kHeapAlignment, 0); 76 CHECK_LT(heap_begin, heap_begin + heap_size); 77 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); 78} 79 80int __tsan_java_fini() { 81 SCOPED_JAVA_FUNC(__tsan_java_fini); 82 DPrintf("#%d: java_fini()\n", thr->tid); 83 CHECK_NE(jctx, 0); 84 // FIXME(dvyukov): this does not call atexit() callbacks. 85 int status = Finalize(thr); 86 DPrintf("#%d: java_fini() = %d\n", thr->tid, status); 87 return status; 88} 89 90void __tsan_java_alloc(jptr ptr, jptr size) { 91 SCOPED_JAVA_FUNC(__tsan_java_alloc); 92 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); 93 CHECK_NE(jctx, 0); 94 CHECK_NE(size, 0); 95 CHECK_EQ(ptr % kHeapAlignment, 0); 96 CHECK_EQ(size % kHeapAlignment, 0); 97 CHECK_GE(ptr, jctx->heap_begin); 98 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 99 100 OnUserAlloc(thr, pc, ptr, size, false); 101} 102 103void __tsan_java_free(jptr ptr, jptr size) { 104 SCOPED_JAVA_FUNC(__tsan_java_free); 105 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); 106 CHECK_NE(jctx, 0); 107 CHECK_NE(size, 0); 108 CHECK_EQ(ptr % kHeapAlignment, 0); 109 CHECK_EQ(size % kHeapAlignment, 0); 110 CHECK_GE(ptr, jctx->heap_begin); 111 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 112 113 ctx->metamap.FreeRange(thr->proc(), ptr, size); 114} 115 116void __tsan_java_move(jptr src, jptr dst, jptr size) { 117 SCOPED_JAVA_FUNC(__tsan_java_move); 118 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); 119 CHECK_NE(jctx, 0); 120 CHECK_NE(size, 0); 121 CHECK_EQ(src % kHeapAlignment, 0); 122 CHECK_EQ(dst % kHeapAlignment, 0); 123 CHECK_EQ(size % kHeapAlignment, 0); 124 CHECK_GE(src, jctx->heap_begin); 125 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 126 CHECK_GE(dst, jctx->heap_begin); 127 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 128 CHECK_NE(dst, src); 129 CHECK_NE(size, 0); 130 131 // Assuming it's not running concurrently with threads that do 132 // memory accesses and mutex operations (stop-the-world phase). 133 ctx->metamap.MoveMemory(src, dst, size); 134 135 // Move shadow. 136 u64 *s = (u64*)MemToShadow(src); 137 u64 *d = (u64*)MemToShadow(dst); 138 u64 *send = (u64*)MemToShadow(src + size); 139 uptr inc = 1; 140 if (dst > src) { 141 s = (u64*)MemToShadow(src + size) - 1; 142 d = (u64*)MemToShadow(dst + size) - 1; 143 send = (u64*)MemToShadow(src) - 1; 144 inc = -1; 145 } 146 for (; s != send; s += inc, d += inc) { 147 *d = *s; 148 *s = 0; 149 } 150} 151 152jptr __tsan_java_find(jptr *from_ptr, jptr to) { 153 SCOPED_JAVA_FUNC(__tsan_java_find); 154 DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); 155 CHECK_EQ((*from_ptr) % kHeapAlignment, 0); 156 CHECK_EQ(to % kHeapAlignment, 0); 157 CHECK_GE(*from_ptr, jctx->heap_begin); 158 CHECK_LE(to, jctx->heap_begin + jctx->heap_size); 159 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { 160 MBlock *b = ctx->metamap.GetBlock(from); 161 if (b) { 162 *from_ptr = from; 163 return b->siz; 164 } 165 } 166 return 0; 167} 168 169void __tsan_java_finalize() { 170 SCOPED_JAVA_FUNC(__tsan_java_finalize); 171 DPrintf("#%d: java_mutex_finalize()\n", thr->tid); 172 AcquireGlobal(thr, 0); 173} 174 175void __tsan_java_mutex_lock(jptr addr) { 176 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock); 177 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 178 CHECK_NE(jctx, 0); 179 CHECK_GE(addr, jctx->heap_begin); 180 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 181 182 MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | 183 MutexFlagDoPreLockOnPostLock); 184} 185 186void __tsan_java_mutex_unlock(jptr addr) { 187 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock); 188 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); 189 CHECK_NE(jctx, 0); 190 CHECK_GE(addr, jctx->heap_begin); 191 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 192 193 MutexUnlock(thr, pc, addr); 194} 195 196void __tsan_java_mutex_read_lock(jptr addr) { 197 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock); 198 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 199 CHECK_NE(jctx, 0); 200 CHECK_GE(addr, jctx->heap_begin); 201 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 202 203 MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit | 204 MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock); 205} 206 207void __tsan_java_mutex_read_unlock(jptr addr) { 208 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock); 209 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 210 CHECK_NE(jctx, 0); 211 CHECK_GE(addr, jctx->heap_begin); 212 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 213 214 MutexReadUnlock(thr, pc, addr); 215} 216 217void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 218 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); 219 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 220 CHECK_NE(jctx, 0); 221 CHECK_GE(addr, jctx->heap_begin); 222 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 223 CHECK_GT(rec, 0); 224 225 MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | 226 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec); 227} 228 229int __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, pc, addr, MutexFlagRecursiveUnlock); 237} 238 239void __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, caller_pc, addr); 247} 248 249void __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, caller_pc, addr); 257} 258 259void __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, caller_pc, addr); 267} 268