258 lines · cpp
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-exception6//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 21using namespace __tsan;22 23const jptr kHeapAlignment = 8;24 25namespace __tsan {26 27struct 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 37static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];38static JavaContext *jctx;39 40MBlock *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 __tsan58 59#define JAVA_FUNC_ENTER(func) \60 ThreadState *thr = cur_thread(); \61 (void)thr;62 63void __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 76int __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 86void __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, 0, ptr, size, false);97}98 99void __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(thr->proc(), ptr, size, false);110}111 112void __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 do127 // memory accesses and mutex operations (stop-the-world phase).128 ctx->metamap.MoveMemory(src, dst, size);129 130 // Clear the destination shadow range.131 // We used to move shadow from src to dst, but the trace format does not132 // support that anymore as it contains addresses of accesses.133 RawShadow *d = MemToShadow(dst);134 RawShadow *dend = MemToShadow(dst + size);135 ShadowSet(d, dend, Shadow::kEmpty);136}137 138jptr __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(from);147 if (b) {148 *from_ptr = from;149 return b->siz;150 }151 }152 return 0;153}154 155void __tsan_java_finalize() {156 JAVA_FUNC_ENTER(__tsan_java_finalize);157 DPrintf("#%d: java_finalize()\n", thr->tid);158 AcquireGlobal(thr);159}160 161void __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, 0, addr,169 MutexFlagLinkerInit | MutexFlagWriteReentrant |170 MutexFlagDoPreLockOnPostLock);171}172 173void __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, 0, addr);181}182 183void __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, 0, addr,191 MutexFlagLinkerInit | MutexFlagWriteReentrant |192 MutexFlagDoPreLockOnPostLock);193}194 195void __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, 0, addr);203}204 205void __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, 0, addr,214 MutexFlagLinkerInit | MutexFlagWriteReentrant |215 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,216 rec);217}218 219int __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, 0, addr, MutexFlagRecursiveUnlock);227}228 229void __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, 0, addr);237}238 239void __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, 0, addr);247}248 249void __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, 0, addr);257}258