xref: /llvm-project/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp (revision b332134921b42796c6b46453eaf2affdc09e3154)
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