15a3bb1a4SNico Weber //===-- tsan_interface_java.cpp -------------------------------------------===//
25a3bb1a4SNico Weber //
35a3bb1a4SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45a3bb1a4SNico Weber // See https://llvm.org/LICENSE.txt for license information.
55a3bb1a4SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a3bb1a4SNico Weber //
75a3bb1a4SNico Weber //===----------------------------------------------------------------------===//
85a3bb1a4SNico Weber //
95a3bb1a4SNico Weber // This file is a part of ThreadSanitizer (TSan), a race detector.
105a3bb1a4SNico Weber //
115a3bb1a4SNico Weber //===----------------------------------------------------------------------===//
125a3bb1a4SNico Weber
135a3bb1a4SNico Weber #include "tsan_interface_java.h"
145a3bb1a4SNico Weber #include "tsan_rtl.h"
155a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_internal_defs.h"
165a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_common.h"
175a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_placement_new.h"
185a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_stacktrace.h"
195a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_procmaps.h"
205a3bb1a4SNico Weber
21c0fa6322SVitaly Buka using namespace __tsan;
225a3bb1a4SNico Weber
235a3bb1a4SNico Weber const jptr kHeapAlignment = 8;
245a3bb1a4SNico Weber
255a3bb1a4SNico Weber namespace __tsan {
265a3bb1a4SNico Weber
275a3bb1a4SNico Weber struct JavaContext {
285a3bb1a4SNico Weber const uptr heap_begin;
295a3bb1a4SNico Weber const uptr heap_size;
305a3bb1a4SNico Weber
JavaContext__tsan::JavaContext315a3bb1a4SNico Weber JavaContext(jptr heap_begin, jptr heap_size)
325a3bb1a4SNico Weber : heap_begin(heap_begin)
335a3bb1a4SNico Weber , heap_size(heap_size) {
345a3bb1a4SNico Weber }
355a3bb1a4SNico Weber };
365a3bb1a4SNico Weber
375a3bb1a4SNico Weber static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
385a3bb1a4SNico Weber static JavaContext *jctx;
395a3bb1a4SNico Weber
JavaHeapBlock(uptr addr,uptr * start)405237b140SDmitry Vyukov MBlock *JavaHeapBlock(uptr addr, uptr *start) {
415237b140SDmitry Vyukov if (!jctx || addr < jctx->heap_begin ||
425237b140SDmitry Vyukov addr >= jctx->heap_begin + jctx->heap_size)
435237b140SDmitry Vyukov return nullptr;
445237b140SDmitry Vyukov for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin;
455237b140SDmitry Vyukov p -= kMetaShadowCell) {
465237b140SDmitry Vyukov MBlock *b = ctx->metamap.GetBlock(p);
475237b140SDmitry Vyukov if (!b)
485237b140SDmitry Vyukov continue;
495237b140SDmitry Vyukov if (p + b->siz <= addr)
505237b140SDmitry Vyukov return nullptr;
515237b140SDmitry Vyukov *start = p;
525237b140SDmitry Vyukov return b;
535237b140SDmitry Vyukov }
545237b140SDmitry Vyukov return nullptr;
555237b140SDmitry Vyukov }
565237b140SDmitry Vyukov
575a3bb1a4SNico Weber } // namespace __tsan
585a3bb1a4SNico Weber
59a1a37ddcSDmitry Vyukov #define JAVA_FUNC_ENTER(func) \
605a3bb1a4SNico Weber ThreadState *thr = cur_thread(); \
61a1a37ddcSDmitry Vyukov (void)thr;
625a3bb1a4SNico Weber
__tsan_java_init(jptr heap_begin,jptr heap_size)635a3bb1a4SNico Weber void __tsan_java_init(jptr heap_begin, jptr heap_size) {
64a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_init);
650bc10d9aSDmitry Vyukov Initialize(thr);
666fe35ef4SDmitry Vyukov DPrintf("#%d: java_init(0x%zx, 0x%zx)\n", thr->tid, heap_begin, heap_size);
6717f650cbSDmitry Vyukov DCHECK_EQ(jctx, 0);
6817f650cbSDmitry Vyukov DCHECK_GT(heap_begin, 0);
6917f650cbSDmitry Vyukov DCHECK_GT(heap_size, 0);
7017f650cbSDmitry Vyukov DCHECK_EQ(heap_begin % kHeapAlignment, 0);
7117f650cbSDmitry Vyukov DCHECK_EQ(heap_size % kHeapAlignment, 0);
7217f650cbSDmitry Vyukov DCHECK_LT(heap_begin, heap_begin + heap_size);
735a3bb1a4SNico Weber jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
745a3bb1a4SNico Weber }
755a3bb1a4SNico Weber
__tsan_java_fini()765a3bb1a4SNico Weber int __tsan_java_fini() {
77a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_fini);
785a3bb1a4SNico Weber DPrintf("#%d: java_fini()\n", thr->tid);
7917f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
805a3bb1a4SNico Weber // FIXME(dvyukov): this does not call atexit() callbacks.
815a3bb1a4SNico Weber int status = Finalize(thr);
825a3bb1a4SNico Weber DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
835a3bb1a4SNico Weber return status;
845a3bb1a4SNico Weber }
855a3bb1a4SNico Weber
__tsan_java_alloc(jptr ptr,jptr size)865a3bb1a4SNico Weber void __tsan_java_alloc(jptr ptr, jptr size) {
87a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_alloc);
886fe35ef4SDmitry Vyukov DPrintf("#%d: java_alloc(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
8917f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
9017f650cbSDmitry Vyukov DCHECK_NE(size, 0);
9117f650cbSDmitry Vyukov DCHECK_EQ(ptr % kHeapAlignment, 0);
9217f650cbSDmitry Vyukov DCHECK_EQ(size % kHeapAlignment, 0);
9317f650cbSDmitry Vyukov DCHECK_GE(ptr, jctx->heap_begin);
9417f650cbSDmitry Vyukov DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
955a3bb1a4SNico Weber
966563bb53SDmitry Vyukov OnUserAlloc(thr, 0, ptr, size, false);
975a3bb1a4SNico Weber }
985a3bb1a4SNico Weber
__tsan_java_free(jptr ptr,jptr size)995a3bb1a4SNico Weber void __tsan_java_free(jptr ptr, jptr size) {
100a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_free);
1016fe35ef4SDmitry Vyukov DPrintf("#%d: java_free(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
10217f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
10317f650cbSDmitry Vyukov DCHECK_NE(size, 0);
10417f650cbSDmitry Vyukov DCHECK_EQ(ptr % kHeapAlignment, 0);
10517f650cbSDmitry Vyukov DCHECK_EQ(size % kHeapAlignment, 0);
10617f650cbSDmitry Vyukov DCHECK_GE(ptr, jctx->heap_begin);
10717f650cbSDmitry Vyukov DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
1085a3bb1a4SNico Weber
109*b3321349SDmitry Vyukov ctx->metamap.FreeRange(thr->proc(), ptr, size, false);
1105a3bb1a4SNico Weber }
1115a3bb1a4SNico Weber
__tsan_java_move(jptr src,jptr dst,jptr size)1125a3bb1a4SNico Weber void __tsan_java_move(jptr src, jptr dst, jptr size) {
113a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_move);
1146fe35ef4SDmitry Vyukov DPrintf("#%d: java_move(0x%zx, 0x%zx, 0x%zx)\n", thr->tid, src, dst, size);
11517f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
11617f650cbSDmitry Vyukov DCHECK_NE(size, 0);
11717f650cbSDmitry Vyukov DCHECK_EQ(src % kHeapAlignment, 0);
11817f650cbSDmitry Vyukov DCHECK_EQ(dst % kHeapAlignment, 0);
11917f650cbSDmitry Vyukov DCHECK_EQ(size % kHeapAlignment, 0);
12017f650cbSDmitry Vyukov DCHECK_GE(src, jctx->heap_begin);
12117f650cbSDmitry Vyukov DCHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
12217f650cbSDmitry Vyukov DCHECK_GE(dst, jctx->heap_begin);
12317f650cbSDmitry Vyukov DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
12417f650cbSDmitry Vyukov DCHECK_NE(dst, src);
12517f650cbSDmitry Vyukov DCHECK_NE(size, 0);
1265a3bb1a4SNico Weber
1275a3bb1a4SNico Weber // Assuming it's not running concurrently with threads that do
1285a3bb1a4SNico Weber // memory accesses and mutex operations (stop-the-world phase).
1295a3bb1a4SNico Weber ctx->metamap.MoveMemory(src, dst, size);
1305a3bb1a4SNico Weber
131db2f870fSDmitry Vyukov // Clear the destination shadow range.
132db2f870fSDmitry Vyukov // We used to move shadow from src to dst, but the trace format does not
133db2f870fSDmitry Vyukov // support that anymore as it contains addresses of accesses.
134a82c7476SDmitry Vyukov RawShadow *d = MemToShadow(dst);
135db2f870fSDmitry Vyukov RawShadow *dend = MemToShadow(dst + size);
136*b3321349SDmitry Vyukov ShadowSet(d, dend, Shadow::kEmpty);
1375a3bb1a4SNico Weber }
1385a3bb1a4SNico Weber
__tsan_java_find(jptr * from_ptr,jptr to)1395a3bb1a4SNico Weber jptr __tsan_java_find(jptr *from_ptr, jptr to) {
140a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_find);
1416fe35ef4SDmitry Vyukov DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
14217f650cbSDmitry Vyukov DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
14317f650cbSDmitry Vyukov DCHECK_EQ(to % kHeapAlignment, 0);
14417f650cbSDmitry Vyukov DCHECK_GE(*from_ptr, jctx->heap_begin);
14517f650cbSDmitry Vyukov DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
1465a3bb1a4SNico Weber for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
1475a3bb1a4SNico Weber MBlock *b = ctx->metamap.GetBlock(from);
1485a3bb1a4SNico Weber if (b) {
1495a3bb1a4SNico Weber *from_ptr = from;
1505a3bb1a4SNico Weber return b->siz;
1515a3bb1a4SNico Weber }
1525a3bb1a4SNico Weber }
1535a3bb1a4SNico Weber return 0;
1545a3bb1a4SNico Weber }
1555a3bb1a4SNico Weber
__tsan_java_finalize()1565a3bb1a4SNico Weber void __tsan_java_finalize() {
157a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_finalize);
158e34d1942SDmitry Vyukov DPrintf("#%d: java_finalize()\n", thr->tid);
1595acdfb7eSDmitry Vyukov AcquireGlobal(thr);
1605a3bb1a4SNico Weber }
1615a3bb1a4SNico Weber
__tsan_java_mutex_lock(jptr addr)1625a3bb1a4SNico Weber void __tsan_java_mutex_lock(jptr addr) {
163a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
1646fe35ef4SDmitry Vyukov DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
16517f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
16617f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
16717f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
1685a3bb1a4SNico Weber
1696563bb53SDmitry Vyukov MutexPostLock(thr, 0, addr,
1706563bb53SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant |
1715a3bb1a4SNico Weber MutexFlagDoPreLockOnPostLock);
1725a3bb1a4SNico Weber }
1735a3bb1a4SNico Weber
__tsan_java_mutex_unlock(jptr addr)1745a3bb1a4SNico Weber void __tsan_java_mutex_unlock(jptr addr) {
175a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
1766fe35ef4SDmitry Vyukov DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
17717f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
17817f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
17917f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
1805a3bb1a4SNico Weber
1816563bb53SDmitry Vyukov MutexUnlock(thr, 0, addr);
1825a3bb1a4SNico Weber }
1835a3bb1a4SNico Weber
__tsan_java_mutex_read_lock(jptr addr)1845a3bb1a4SNico Weber void __tsan_java_mutex_read_lock(jptr addr) {
185a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
1866fe35ef4SDmitry Vyukov DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
18717f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
18817f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
18917f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
1905a3bb1a4SNico Weber
1916563bb53SDmitry Vyukov MutexPostReadLock(thr, 0, addr,
1926563bb53SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant |
1936563bb53SDmitry Vyukov MutexFlagDoPreLockOnPostLock);
1945a3bb1a4SNico Weber }
1955a3bb1a4SNico Weber
__tsan_java_mutex_read_unlock(jptr addr)1965a3bb1a4SNico Weber void __tsan_java_mutex_read_unlock(jptr addr) {
197a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
1986fe35ef4SDmitry Vyukov DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
19917f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
20017f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
20117f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
2025a3bb1a4SNico Weber
2036563bb53SDmitry Vyukov MutexReadUnlock(thr, 0, addr);
2045a3bb1a4SNico Weber }
2055a3bb1a4SNico Weber
__tsan_java_mutex_lock_rec(jptr addr,int rec)2065a3bb1a4SNico Weber void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
207a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
2086fe35ef4SDmitry Vyukov DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
20917f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
21017f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
21117f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
21217f650cbSDmitry Vyukov DCHECK_GT(rec, 0);
2135a3bb1a4SNico Weber
2146563bb53SDmitry Vyukov MutexPostLock(thr, 0, addr,
2156563bb53SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant |
2166563bb53SDmitry Vyukov MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
2176563bb53SDmitry Vyukov rec);
2185a3bb1a4SNico Weber }
2195a3bb1a4SNico Weber
__tsan_java_mutex_unlock_rec(jptr addr)2205a3bb1a4SNico Weber int __tsan_java_mutex_unlock_rec(jptr addr) {
221a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
2226fe35ef4SDmitry Vyukov DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
22317f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
22417f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
22517f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
2265a3bb1a4SNico Weber
2276563bb53SDmitry Vyukov return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
2285a3bb1a4SNico Weber }
2295a3bb1a4SNico Weber
__tsan_java_acquire(jptr addr)2305a3bb1a4SNico Weber void __tsan_java_acquire(jptr addr) {
231a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_acquire);
2326fe35ef4SDmitry Vyukov DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
23317f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
23417f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
23517f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
2365a3bb1a4SNico Weber
2376563bb53SDmitry Vyukov Acquire(thr, 0, addr);
2385a3bb1a4SNico Weber }
2395a3bb1a4SNico Weber
__tsan_java_release(jptr addr)2405a3bb1a4SNico Weber void __tsan_java_release(jptr addr) {
241a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_release);
2426fe35ef4SDmitry Vyukov DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
24317f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
24417f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
24517f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
2465a3bb1a4SNico Weber
2476563bb53SDmitry Vyukov Release(thr, 0, addr);
2485a3bb1a4SNico Weber }
2495a3bb1a4SNico Weber
__tsan_java_release_store(jptr addr)2505a3bb1a4SNico Weber void __tsan_java_release_store(jptr addr) {
251a1a37ddcSDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_release);
2526fe35ef4SDmitry Vyukov DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
25317f650cbSDmitry Vyukov DCHECK_NE(jctx, 0);
25417f650cbSDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
25517f650cbSDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
2565a3bb1a4SNico Weber
2576563bb53SDmitry Vyukov ReleaseStore(thr, 0, addr);
2585a3bb1a4SNico Weber }
259