1*8e93d4c9SDmitry Vyukov //===-- tsan_interface_java.cpp -------------------------------------------===//
2*8e93d4c9SDmitry Vyukov //
3*8e93d4c9SDmitry Vyukov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8e93d4c9SDmitry Vyukov // See https://llvm.org/LICENSE.txt for license information.
5*8e93d4c9SDmitry Vyukov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8e93d4c9SDmitry Vyukov //
7*8e93d4c9SDmitry Vyukov //===----------------------------------------------------------------------===//
8*8e93d4c9SDmitry Vyukov //
9*8e93d4c9SDmitry Vyukov // This file is a part of ThreadSanitizer (TSan), a race detector.
10*8e93d4c9SDmitry Vyukov //
11*8e93d4c9SDmitry Vyukov //===----------------------------------------------------------------------===//
12*8e93d4c9SDmitry Vyukov
13*8e93d4c9SDmitry Vyukov #include "tsan_interface_java.h"
14*8e93d4c9SDmitry Vyukov #include "tsan_rtl.h"
15*8e93d4c9SDmitry Vyukov #include "sanitizer_common/sanitizer_internal_defs.h"
16*8e93d4c9SDmitry Vyukov #include "sanitizer_common/sanitizer_common.h"
17*8e93d4c9SDmitry Vyukov #include "sanitizer_common/sanitizer_placement_new.h"
18*8e93d4c9SDmitry Vyukov #include "sanitizer_common/sanitizer_stacktrace.h"
19*8e93d4c9SDmitry Vyukov #include "sanitizer_common/sanitizer_procmaps.h"
20*8e93d4c9SDmitry Vyukov
21*8e93d4c9SDmitry Vyukov using namespace __tsan;
22*8e93d4c9SDmitry Vyukov
23*8e93d4c9SDmitry Vyukov const jptr kHeapAlignment = 8;
24*8e93d4c9SDmitry Vyukov
25*8e93d4c9SDmitry Vyukov namespace __tsan {
26*8e93d4c9SDmitry Vyukov
27*8e93d4c9SDmitry Vyukov struct JavaContext {
28*8e93d4c9SDmitry Vyukov const uptr heap_begin;
29*8e93d4c9SDmitry Vyukov const uptr heap_size;
30*8e93d4c9SDmitry Vyukov
JavaContext__tsan::JavaContext31*8e93d4c9SDmitry Vyukov JavaContext(jptr heap_begin, jptr heap_size)
32*8e93d4c9SDmitry Vyukov : heap_begin(heap_begin)
33*8e93d4c9SDmitry Vyukov , heap_size(heap_size) {
34*8e93d4c9SDmitry Vyukov }
35*8e93d4c9SDmitry Vyukov };
36*8e93d4c9SDmitry Vyukov
37*8e93d4c9SDmitry Vyukov static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
38*8e93d4c9SDmitry Vyukov static JavaContext *jctx;
39*8e93d4c9SDmitry Vyukov
JavaHeapBlock(uptr addr,uptr * start)40*8e93d4c9SDmitry Vyukov MBlock *JavaHeapBlock(uptr addr, uptr *start) {
41*8e93d4c9SDmitry Vyukov if (!jctx || addr < jctx->heap_begin ||
42*8e93d4c9SDmitry Vyukov addr >= jctx->heap_begin + jctx->heap_size)
43*8e93d4c9SDmitry Vyukov return nullptr;
44*8e93d4c9SDmitry Vyukov for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin;
45*8e93d4c9SDmitry Vyukov p -= kMetaShadowCell) {
46*8e93d4c9SDmitry Vyukov MBlock *b = ctx->metamap.GetBlock(p);
47*8e93d4c9SDmitry Vyukov if (!b)
48*8e93d4c9SDmitry Vyukov continue;
49*8e93d4c9SDmitry Vyukov if (p + b->siz <= addr)
50*8e93d4c9SDmitry Vyukov return nullptr;
51*8e93d4c9SDmitry Vyukov *start = p;
52*8e93d4c9SDmitry Vyukov return b;
53*8e93d4c9SDmitry Vyukov }
54*8e93d4c9SDmitry Vyukov return nullptr;
55*8e93d4c9SDmitry Vyukov }
56*8e93d4c9SDmitry Vyukov
57*8e93d4c9SDmitry Vyukov } // namespace __tsan
58*8e93d4c9SDmitry Vyukov
59*8e93d4c9SDmitry Vyukov #define JAVA_FUNC_ENTER(func) \
60*8e93d4c9SDmitry Vyukov ThreadState *thr = cur_thread(); \
61*8e93d4c9SDmitry Vyukov (void)thr;
62*8e93d4c9SDmitry Vyukov
__tsan_java_init(jptr heap_begin,jptr heap_size)63*8e93d4c9SDmitry Vyukov void __tsan_java_init(jptr heap_begin, jptr heap_size) {
64*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_init);
65*8e93d4c9SDmitry Vyukov Initialize(thr);
66*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_init(0x%zx, 0x%zx)\n", thr->tid, heap_begin, heap_size);
67*8e93d4c9SDmitry Vyukov DCHECK_EQ(jctx, 0);
68*8e93d4c9SDmitry Vyukov DCHECK_GT(heap_begin, 0);
69*8e93d4c9SDmitry Vyukov DCHECK_GT(heap_size, 0);
70*8e93d4c9SDmitry Vyukov DCHECK_EQ(heap_begin % kHeapAlignment, 0);
71*8e93d4c9SDmitry Vyukov DCHECK_EQ(heap_size % kHeapAlignment, 0);
72*8e93d4c9SDmitry Vyukov DCHECK_LT(heap_begin, heap_begin + heap_size);
73*8e93d4c9SDmitry Vyukov jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
74*8e93d4c9SDmitry Vyukov }
75*8e93d4c9SDmitry Vyukov
__tsan_java_fini()76*8e93d4c9SDmitry Vyukov int __tsan_java_fini() {
77*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_fini);
78*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_fini()\n", thr->tid);
79*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
80*8e93d4c9SDmitry Vyukov // FIXME(dvyukov): this does not call atexit() callbacks.
81*8e93d4c9SDmitry Vyukov int status = Finalize(thr);
82*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
83*8e93d4c9SDmitry Vyukov return status;
84*8e93d4c9SDmitry Vyukov }
85*8e93d4c9SDmitry Vyukov
__tsan_java_alloc(jptr ptr,jptr size)86*8e93d4c9SDmitry Vyukov void __tsan_java_alloc(jptr ptr, jptr size) {
87*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_alloc);
88*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_alloc(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
89*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
90*8e93d4c9SDmitry Vyukov DCHECK_NE(size, 0);
91*8e93d4c9SDmitry Vyukov DCHECK_EQ(ptr % kHeapAlignment, 0);
92*8e93d4c9SDmitry Vyukov DCHECK_EQ(size % kHeapAlignment, 0);
93*8e93d4c9SDmitry Vyukov DCHECK_GE(ptr, jctx->heap_begin);
94*8e93d4c9SDmitry Vyukov DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
95*8e93d4c9SDmitry Vyukov
96*8e93d4c9SDmitry Vyukov OnUserAlloc(thr, 0, ptr, size, false);
97*8e93d4c9SDmitry Vyukov }
98*8e93d4c9SDmitry Vyukov
__tsan_java_free(jptr ptr,jptr size)99*8e93d4c9SDmitry Vyukov void __tsan_java_free(jptr ptr, jptr size) {
100*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_free);
101*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_free(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
102*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
103*8e93d4c9SDmitry Vyukov DCHECK_NE(size, 0);
104*8e93d4c9SDmitry Vyukov DCHECK_EQ(ptr % kHeapAlignment, 0);
105*8e93d4c9SDmitry Vyukov DCHECK_EQ(size % kHeapAlignment, 0);
106*8e93d4c9SDmitry Vyukov DCHECK_GE(ptr, jctx->heap_begin);
107*8e93d4c9SDmitry Vyukov DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
108*8e93d4c9SDmitry Vyukov
109*8e93d4c9SDmitry Vyukov ctx->metamap.FreeRange(thr->proc(), ptr, size);
110*8e93d4c9SDmitry Vyukov }
111*8e93d4c9SDmitry Vyukov
__tsan_java_move(jptr src,jptr dst,jptr size)112*8e93d4c9SDmitry Vyukov void __tsan_java_move(jptr src, jptr dst, jptr size) {
113*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_move);
114*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_move(0x%zx, 0x%zx, 0x%zx)\n", thr->tid, src, dst, size);
115*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
116*8e93d4c9SDmitry Vyukov DCHECK_NE(size, 0);
117*8e93d4c9SDmitry Vyukov DCHECK_EQ(src % kHeapAlignment, 0);
118*8e93d4c9SDmitry Vyukov DCHECK_EQ(dst % kHeapAlignment, 0);
119*8e93d4c9SDmitry Vyukov DCHECK_EQ(size % kHeapAlignment, 0);
120*8e93d4c9SDmitry Vyukov DCHECK_GE(src, jctx->heap_begin);
121*8e93d4c9SDmitry Vyukov DCHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
122*8e93d4c9SDmitry Vyukov DCHECK_GE(dst, jctx->heap_begin);
123*8e93d4c9SDmitry Vyukov DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
124*8e93d4c9SDmitry Vyukov DCHECK_NE(dst, src);
125*8e93d4c9SDmitry Vyukov DCHECK_NE(size, 0);
126*8e93d4c9SDmitry Vyukov
127*8e93d4c9SDmitry Vyukov // Assuming it's not running concurrently with threads that do
128*8e93d4c9SDmitry Vyukov // memory accesses and mutex operations (stop-the-world phase).
129*8e93d4c9SDmitry Vyukov ctx->metamap.MoveMemory(src, dst, size);
130*8e93d4c9SDmitry Vyukov
131*8e93d4c9SDmitry Vyukov // Clear the destination shadow range.
132*8e93d4c9SDmitry Vyukov // We used to move shadow from src to dst, but the trace format does not
133*8e93d4c9SDmitry Vyukov // support that anymore as it contains addresses of accesses.
134*8e93d4c9SDmitry Vyukov RawShadow *d = MemToShadow(dst);
135*8e93d4c9SDmitry Vyukov RawShadow *dend = MemToShadow(dst + size);
136*8e93d4c9SDmitry Vyukov internal_memset(d, 0, (dend - d) * sizeof(*d));
137*8e93d4c9SDmitry Vyukov }
138*8e93d4c9SDmitry Vyukov
__tsan_java_find(jptr * from_ptr,jptr to)139*8e93d4c9SDmitry Vyukov jptr __tsan_java_find(jptr *from_ptr, jptr to) {
140*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_find);
141*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
142*8e93d4c9SDmitry Vyukov DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
143*8e93d4c9SDmitry Vyukov DCHECK_EQ(to % kHeapAlignment, 0);
144*8e93d4c9SDmitry Vyukov DCHECK_GE(*from_ptr, jctx->heap_begin);
145*8e93d4c9SDmitry Vyukov DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
146*8e93d4c9SDmitry Vyukov for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
147*8e93d4c9SDmitry Vyukov MBlock *b = ctx->metamap.GetBlock(from);
148*8e93d4c9SDmitry Vyukov if (b) {
149*8e93d4c9SDmitry Vyukov *from_ptr = from;
150*8e93d4c9SDmitry Vyukov return b->siz;
151*8e93d4c9SDmitry Vyukov }
152*8e93d4c9SDmitry Vyukov }
153*8e93d4c9SDmitry Vyukov return 0;
154*8e93d4c9SDmitry Vyukov }
155*8e93d4c9SDmitry Vyukov
__tsan_java_finalize()156*8e93d4c9SDmitry Vyukov void __tsan_java_finalize() {
157*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_finalize);
158*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_finalize()\n", thr->tid);
159*8e93d4c9SDmitry Vyukov AcquireGlobal(thr);
160*8e93d4c9SDmitry Vyukov }
161*8e93d4c9SDmitry Vyukov
__tsan_java_mutex_lock(jptr addr)162*8e93d4c9SDmitry Vyukov void __tsan_java_mutex_lock(jptr addr) {
163*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
164*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
165*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
166*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
167*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
168*8e93d4c9SDmitry Vyukov
169*8e93d4c9SDmitry Vyukov MutexPostLock(thr, 0, addr,
170*8e93d4c9SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant |
171*8e93d4c9SDmitry Vyukov MutexFlagDoPreLockOnPostLock);
172*8e93d4c9SDmitry Vyukov }
173*8e93d4c9SDmitry Vyukov
__tsan_java_mutex_unlock(jptr addr)174*8e93d4c9SDmitry Vyukov void __tsan_java_mutex_unlock(jptr addr) {
175*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
176*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
177*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
178*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
179*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
180*8e93d4c9SDmitry Vyukov
181*8e93d4c9SDmitry Vyukov MutexUnlock(thr, 0, addr);
182*8e93d4c9SDmitry Vyukov }
183*8e93d4c9SDmitry Vyukov
__tsan_java_mutex_read_lock(jptr addr)184*8e93d4c9SDmitry Vyukov void __tsan_java_mutex_read_lock(jptr addr) {
185*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
186*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
187*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
188*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
189*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
190*8e93d4c9SDmitry Vyukov
191*8e93d4c9SDmitry Vyukov MutexPostReadLock(thr, 0, addr,
192*8e93d4c9SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant |
193*8e93d4c9SDmitry Vyukov MutexFlagDoPreLockOnPostLock);
194*8e93d4c9SDmitry Vyukov }
195*8e93d4c9SDmitry Vyukov
__tsan_java_mutex_read_unlock(jptr addr)196*8e93d4c9SDmitry Vyukov void __tsan_java_mutex_read_unlock(jptr addr) {
197*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
198*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
199*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
200*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
201*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
202*8e93d4c9SDmitry Vyukov
203*8e93d4c9SDmitry Vyukov MutexReadUnlock(thr, 0, addr);
204*8e93d4c9SDmitry Vyukov }
205*8e93d4c9SDmitry Vyukov
__tsan_java_mutex_lock_rec(jptr addr,int rec)206*8e93d4c9SDmitry Vyukov void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
207*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
208*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
209*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
210*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
211*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
212*8e93d4c9SDmitry Vyukov DCHECK_GT(rec, 0);
213*8e93d4c9SDmitry Vyukov
214*8e93d4c9SDmitry Vyukov MutexPostLock(thr, 0, addr,
215*8e93d4c9SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant |
216*8e93d4c9SDmitry Vyukov MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
217*8e93d4c9SDmitry Vyukov rec);
218*8e93d4c9SDmitry Vyukov }
219*8e93d4c9SDmitry Vyukov
__tsan_java_mutex_unlock_rec(jptr addr)220*8e93d4c9SDmitry Vyukov int __tsan_java_mutex_unlock_rec(jptr addr) {
221*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
222*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
223*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
224*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
225*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
226*8e93d4c9SDmitry Vyukov
227*8e93d4c9SDmitry Vyukov return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
228*8e93d4c9SDmitry Vyukov }
229*8e93d4c9SDmitry Vyukov
__tsan_java_acquire(jptr addr)230*8e93d4c9SDmitry Vyukov void __tsan_java_acquire(jptr addr) {
231*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_acquire);
232*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
233*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
234*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
235*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
236*8e93d4c9SDmitry Vyukov
237*8e93d4c9SDmitry Vyukov Acquire(thr, 0, addr);
238*8e93d4c9SDmitry Vyukov }
239*8e93d4c9SDmitry Vyukov
__tsan_java_release(jptr addr)240*8e93d4c9SDmitry Vyukov void __tsan_java_release(jptr addr) {
241*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_release);
242*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
243*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
244*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
245*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
246*8e93d4c9SDmitry Vyukov
247*8e93d4c9SDmitry Vyukov Release(thr, 0, addr);
248*8e93d4c9SDmitry Vyukov }
249*8e93d4c9SDmitry Vyukov
__tsan_java_release_store(jptr addr)250*8e93d4c9SDmitry Vyukov void __tsan_java_release_store(jptr addr) {
251*8e93d4c9SDmitry Vyukov JAVA_FUNC_ENTER(__tsan_java_release);
252*8e93d4c9SDmitry Vyukov DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
253*8e93d4c9SDmitry Vyukov DCHECK_NE(jctx, 0);
254*8e93d4c9SDmitry Vyukov DCHECK_GE(addr, jctx->heap_begin);
255*8e93d4c9SDmitry Vyukov DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
256*8e93d4c9SDmitry Vyukov
257*8e93d4c9SDmitry Vyukov ReleaseStore(thr, 0, addr);
258*8e93d4c9SDmitry Vyukov }
259