168d75effSDimitry Andric //===-- tsan_interface_java.cpp -------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "tsan_interface_java.h"
1468d75effSDimitry Andric #include "tsan_rtl.h"
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_procmaps.h"
2068d75effSDimitry Andric 
2168d75effSDimitry Andric using namespace __tsan;
2268d75effSDimitry Andric 
2368d75effSDimitry Andric const jptr kHeapAlignment = 8;
2468d75effSDimitry Andric 
2568d75effSDimitry Andric namespace __tsan {
2668d75effSDimitry Andric 
2768d75effSDimitry Andric struct JavaContext {
2868d75effSDimitry Andric   const uptr heap_begin;
2968d75effSDimitry Andric   const uptr heap_size;
3068d75effSDimitry Andric 
JavaContext__tsan::JavaContext3168d75effSDimitry Andric   JavaContext(jptr heap_begin, jptr heap_size)
3268d75effSDimitry Andric       : heap_begin(heap_begin)
3368d75effSDimitry Andric       , heap_size(heap_size) {
3468d75effSDimitry Andric   }
3568d75effSDimitry Andric };
3668d75effSDimitry Andric 
3768d75effSDimitry Andric class ScopedJavaFunc {
3868d75effSDimitry Andric  public:
ScopedJavaFunc(ThreadState * thr,uptr pc)3968d75effSDimitry Andric   ScopedJavaFunc(ThreadState *thr, uptr pc)
4068d75effSDimitry Andric       : thr_(thr) {
4168d75effSDimitry Andric     Initialize(thr_);
4268d75effSDimitry Andric     FuncEntry(thr, pc);
4368d75effSDimitry Andric   }
4468d75effSDimitry Andric 
~ScopedJavaFunc()4568d75effSDimitry Andric   ~ScopedJavaFunc() {
4668d75effSDimitry Andric     FuncExit(thr_);
4768d75effSDimitry Andric     // FIXME(dvyukov): process pending signals.
4868d75effSDimitry Andric   }
4968d75effSDimitry Andric 
5068d75effSDimitry Andric  private:
5168d75effSDimitry Andric   ThreadState *thr_;
5268d75effSDimitry Andric };
5368d75effSDimitry Andric 
5468d75effSDimitry Andric static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
5568d75effSDimitry Andric static JavaContext *jctx;
5668d75effSDimitry Andric 
5768d75effSDimitry Andric }  // namespace __tsan
5868d75effSDimitry Andric 
5968d75effSDimitry Andric #define SCOPED_JAVA_FUNC(func) \
6068d75effSDimitry Andric   ThreadState *thr = cur_thread(); \
6168d75effSDimitry Andric   const uptr caller_pc = GET_CALLER_PC(); \
6268d75effSDimitry Andric   const uptr pc = StackTrace::GetCurrentPc(); \
6368d75effSDimitry Andric   (void)pc; \
6468d75effSDimitry Andric   ScopedJavaFunc scoped(thr, caller_pc); \
6568d75effSDimitry Andric /**/
6668d75effSDimitry Andric 
__tsan_java_init(jptr heap_begin,jptr heap_size)6768d75effSDimitry Andric void __tsan_java_init(jptr heap_begin, jptr heap_size) {
6868d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_init);
6968d75effSDimitry Andric   DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
7068d75effSDimitry Andric   CHECK_EQ(jctx, 0);
7168d75effSDimitry Andric   CHECK_GT(heap_begin, 0);
7268d75effSDimitry Andric   CHECK_GT(heap_size, 0);
7368d75effSDimitry Andric   CHECK_EQ(heap_begin % kHeapAlignment, 0);
7468d75effSDimitry Andric   CHECK_EQ(heap_size % kHeapAlignment, 0);
7568d75effSDimitry Andric   CHECK_LT(heap_begin, heap_begin + heap_size);
7668d75effSDimitry Andric   jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
7768d75effSDimitry Andric }
7868d75effSDimitry Andric 
__tsan_java_fini()7968d75effSDimitry Andric int  __tsan_java_fini() {
8068d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_fini);
8168d75effSDimitry Andric   DPrintf("#%d: java_fini()\n", thr->tid);
8268d75effSDimitry Andric   CHECK_NE(jctx, 0);
8368d75effSDimitry Andric   // FIXME(dvyukov): this does not call atexit() callbacks.
8468d75effSDimitry Andric   int status = Finalize(thr);
8568d75effSDimitry Andric   DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
8668d75effSDimitry Andric   return status;
8768d75effSDimitry Andric }
8868d75effSDimitry Andric 
__tsan_java_alloc(jptr ptr,jptr size)8968d75effSDimitry Andric void __tsan_java_alloc(jptr ptr, jptr size) {
9068d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_alloc);
9168d75effSDimitry Andric   DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
9268d75effSDimitry Andric   CHECK_NE(jctx, 0);
9368d75effSDimitry Andric   CHECK_NE(size, 0);
9468d75effSDimitry Andric   CHECK_EQ(ptr % kHeapAlignment, 0);
9568d75effSDimitry Andric   CHECK_EQ(size % kHeapAlignment, 0);
9668d75effSDimitry Andric   CHECK_GE(ptr, jctx->heap_begin);
9768d75effSDimitry Andric   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
9868d75effSDimitry Andric 
9968d75effSDimitry Andric   OnUserAlloc(thr, pc, ptr, size, false);
10068d75effSDimitry Andric }
10168d75effSDimitry Andric 
__tsan_java_free(jptr ptr,jptr size)10268d75effSDimitry Andric void __tsan_java_free(jptr ptr, jptr size) {
10368d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_free);
10468d75effSDimitry Andric   DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
10568d75effSDimitry Andric   CHECK_NE(jctx, 0);
10668d75effSDimitry Andric   CHECK_NE(size, 0);
10768d75effSDimitry Andric   CHECK_EQ(ptr % kHeapAlignment, 0);
10868d75effSDimitry Andric   CHECK_EQ(size % kHeapAlignment, 0);
10968d75effSDimitry Andric   CHECK_GE(ptr, jctx->heap_begin);
11068d75effSDimitry Andric   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
11168d75effSDimitry Andric 
11268d75effSDimitry Andric   ctx->metamap.FreeRange(thr->proc(), ptr, size);
11368d75effSDimitry Andric }
11468d75effSDimitry Andric 
__tsan_java_move(jptr src,jptr dst,jptr size)11568d75effSDimitry Andric void __tsan_java_move(jptr src, jptr dst, jptr size) {
11668d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_move);
11768d75effSDimitry Andric   DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
11868d75effSDimitry Andric   CHECK_NE(jctx, 0);
11968d75effSDimitry Andric   CHECK_NE(size, 0);
12068d75effSDimitry Andric   CHECK_EQ(src % kHeapAlignment, 0);
12168d75effSDimitry Andric   CHECK_EQ(dst % kHeapAlignment, 0);
12268d75effSDimitry Andric   CHECK_EQ(size % kHeapAlignment, 0);
12368d75effSDimitry Andric   CHECK_GE(src, jctx->heap_begin);
12468d75effSDimitry Andric   CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
12568d75effSDimitry Andric   CHECK_GE(dst, jctx->heap_begin);
12668d75effSDimitry Andric   CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
12768d75effSDimitry Andric   CHECK_NE(dst, src);
12868d75effSDimitry Andric   CHECK_NE(size, 0);
12968d75effSDimitry Andric 
13068d75effSDimitry Andric   // Assuming it's not running concurrently with threads that do
13168d75effSDimitry Andric   // memory accesses and mutex operations (stop-the-world phase).
13268d75effSDimitry Andric   ctx->metamap.MoveMemory(src, dst, size);
13368d75effSDimitry Andric 
13468d75effSDimitry Andric   // Move shadow.
13568d75effSDimitry Andric   u64 *s = (u64*)MemToShadow(src);
13668d75effSDimitry Andric   u64 *d = (u64*)MemToShadow(dst);
13768d75effSDimitry Andric   u64 *send = (u64*)MemToShadow(src + size);
13868d75effSDimitry Andric   uptr inc = 1;
13968d75effSDimitry Andric   if (dst > src) {
14068d75effSDimitry Andric     s = (u64*)MemToShadow(src + size) - 1;
14168d75effSDimitry Andric     d = (u64*)MemToShadow(dst + size) - 1;
14268d75effSDimitry Andric     send = (u64*)MemToShadow(src) - 1;
14368d75effSDimitry Andric     inc = -1;
14468d75effSDimitry Andric   }
14568d75effSDimitry Andric   for (; s != send; s += inc, d += inc) {
14668d75effSDimitry Andric     *d = *s;
14768d75effSDimitry Andric     *s = 0;
14868d75effSDimitry Andric   }
14968d75effSDimitry Andric }
15068d75effSDimitry Andric 
__tsan_java_find(jptr * from_ptr,jptr to)15168d75effSDimitry Andric jptr __tsan_java_find(jptr *from_ptr, jptr to) {
15268d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_find);
15368d75effSDimitry Andric   DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to);
15468d75effSDimitry Andric   CHECK_EQ((*from_ptr) % kHeapAlignment, 0);
15568d75effSDimitry Andric   CHECK_EQ(to % kHeapAlignment, 0);
15668d75effSDimitry Andric   CHECK_GE(*from_ptr, jctx->heap_begin);
15768d75effSDimitry Andric   CHECK_LE(to, jctx->heap_begin + jctx->heap_size);
15868d75effSDimitry Andric   for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
15968d75effSDimitry Andric     MBlock *b = ctx->metamap.GetBlock(from);
16068d75effSDimitry Andric     if (b) {
16168d75effSDimitry Andric       *from_ptr = from;
16268d75effSDimitry Andric       return b->siz;
16368d75effSDimitry Andric     }
16468d75effSDimitry Andric   }
16568d75effSDimitry Andric   return 0;
16668d75effSDimitry Andric }
16768d75effSDimitry Andric 
__tsan_java_finalize()16868d75effSDimitry Andric void __tsan_java_finalize() {
16968d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_finalize);
17068d75effSDimitry Andric   DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
17168d75effSDimitry Andric   AcquireGlobal(thr, 0);
17268d75effSDimitry Andric }
17368d75effSDimitry Andric 
__tsan_java_mutex_lock(jptr addr)17468d75effSDimitry Andric void __tsan_java_mutex_lock(jptr addr) {
17568d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
17668d75effSDimitry Andric   DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
17768d75effSDimitry Andric   CHECK_NE(jctx, 0);
17868d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
17968d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
18068d75effSDimitry Andric 
18168d75effSDimitry Andric   MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
18268d75effSDimitry Andric       MutexFlagDoPreLockOnPostLock);
18368d75effSDimitry Andric }
18468d75effSDimitry Andric 
__tsan_java_mutex_unlock(jptr addr)18568d75effSDimitry Andric void __tsan_java_mutex_unlock(jptr addr) {
18668d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
18768d75effSDimitry Andric   DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
18868d75effSDimitry Andric   CHECK_NE(jctx, 0);
18968d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
19068d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
19168d75effSDimitry Andric 
19268d75effSDimitry Andric   MutexUnlock(thr, pc, addr);
19368d75effSDimitry Andric }
19468d75effSDimitry Andric 
__tsan_java_mutex_read_lock(jptr addr)19568d75effSDimitry Andric void __tsan_java_mutex_read_lock(jptr addr) {
19668d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
19768d75effSDimitry Andric   DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
19868d75effSDimitry Andric   CHECK_NE(jctx, 0);
19968d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
20068d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
20168d75effSDimitry Andric 
20268d75effSDimitry Andric   MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit |
20368d75effSDimitry Andric       MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock);
20468d75effSDimitry Andric }
20568d75effSDimitry Andric 
__tsan_java_mutex_read_unlock(jptr addr)20668d75effSDimitry Andric void __tsan_java_mutex_read_unlock(jptr addr) {
20768d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
20868d75effSDimitry Andric   DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
20968d75effSDimitry Andric   CHECK_NE(jctx, 0);
21068d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
21168d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
21268d75effSDimitry Andric 
21368d75effSDimitry Andric   MutexReadUnlock(thr, pc, addr);
21468d75effSDimitry Andric }
21568d75effSDimitry Andric 
__tsan_java_mutex_lock_rec(jptr addr,int rec)21668d75effSDimitry Andric void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
21768d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
21868d75effSDimitry Andric   DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
21968d75effSDimitry Andric   CHECK_NE(jctx, 0);
22068d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
22168d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
22268d75effSDimitry Andric   CHECK_GT(rec, 0);
22368d75effSDimitry Andric 
22468d75effSDimitry Andric   MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
22568d75effSDimitry Andric       MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec);
22668d75effSDimitry Andric }
22768d75effSDimitry Andric 
__tsan_java_mutex_unlock_rec(jptr addr)22868d75effSDimitry Andric int __tsan_java_mutex_unlock_rec(jptr addr) {
22968d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
23068d75effSDimitry Andric   DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
23168d75effSDimitry Andric   CHECK_NE(jctx, 0);
23268d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
23368d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
23468d75effSDimitry Andric 
23568d75effSDimitry Andric   return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock);
23668d75effSDimitry Andric }
23768d75effSDimitry Andric 
__tsan_java_acquire(jptr addr)23868d75effSDimitry Andric void __tsan_java_acquire(jptr addr) {
23968d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_acquire);
24068d75effSDimitry Andric   DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr);
24168d75effSDimitry Andric   CHECK_NE(jctx, 0);
24268d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
24368d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
24468d75effSDimitry Andric 
24568d75effSDimitry Andric   Acquire(thr, caller_pc, addr);
24668d75effSDimitry Andric }
24768d75effSDimitry Andric 
__tsan_java_release(jptr addr)24868d75effSDimitry Andric void __tsan_java_release(jptr addr) {
24968d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_release);
25068d75effSDimitry Andric   DPrintf("#%d: java_release(%p)\n", thr->tid, addr);
25168d75effSDimitry Andric   CHECK_NE(jctx, 0);
25268d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
25368d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
25468d75effSDimitry Andric 
25568d75effSDimitry Andric   Release(thr, caller_pc, addr);
25668d75effSDimitry Andric }
25768d75effSDimitry Andric 
__tsan_java_release_store(jptr addr)25868d75effSDimitry Andric void __tsan_java_release_store(jptr addr) {
25968d75effSDimitry Andric   SCOPED_JAVA_FUNC(__tsan_java_release);
26068d75effSDimitry Andric   DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr);
26168d75effSDimitry Andric   CHECK_NE(jctx, 0);
26268d75effSDimitry Andric   CHECK_GE(addr, jctx->heap_begin);
26368d75effSDimitry Andric   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
26468d75effSDimitry Andric 
26568d75effSDimitry Andric   ReleaseStore(thr, caller_pc, addr);
26668d75effSDimitry Andric }
267