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 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
3868d75effSDimitry Andric static JavaContext *jctx;
3968d75effSDimitry Andric
JavaHeapBlock(uptr addr,uptr * start)40349cc55cSDimitry Andric MBlock *JavaHeapBlock(uptr addr, uptr *start) {
41349cc55cSDimitry Andric if (!jctx || addr < jctx->heap_begin ||
42349cc55cSDimitry Andric addr >= jctx->heap_begin + jctx->heap_size)
43349cc55cSDimitry Andric return nullptr;
44349cc55cSDimitry Andric for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin;
45349cc55cSDimitry Andric p -= kMetaShadowCell) {
46349cc55cSDimitry Andric MBlock *b = ctx->metamap.GetBlock(p);
47349cc55cSDimitry Andric if (!b)
48349cc55cSDimitry Andric continue;
49349cc55cSDimitry Andric if (p + b->siz <= addr)
50349cc55cSDimitry Andric return nullptr;
51349cc55cSDimitry Andric *start = p;
52349cc55cSDimitry Andric return b;
53349cc55cSDimitry Andric }
54349cc55cSDimitry Andric return nullptr;
55349cc55cSDimitry Andric }
56349cc55cSDimitry Andric
5768d75effSDimitry Andric } // namespace __tsan
5868d75effSDimitry Andric
59349cc55cSDimitry Andric #define JAVA_FUNC_ENTER(func) \
6068d75effSDimitry Andric ThreadState *thr = cur_thread(); \
61349cc55cSDimitry Andric (void)thr;
6268d75effSDimitry Andric
__tsan_java_init(jptr heap_begin,jptr heap_size)6368d75effSDimitry Andric void __tsan_java_init(jptr heap_begin, jptr heap_size) {
64349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_init);
65349cc55cSDimitry Andric Initialize(thr);
66349cc55cSDimitry Andric DPrintf("#%d: java_init(0x%zx, 0x%zx)\n", thr->tid, heap_begin, heap_size);
67349cc55cSDimitry Andric DCHECK_EQ(jctx, 0);
68349cc55cSDimitry Andric DCHECK_GT(heap_begin, 0);
69349cc55cSDimitry Andric DCHECK_GT(heap_size, 0);
70349cc55cSDimitry Andric DCHECK_EQ(heap_begin % kHeapAlignment, 0);
71349cc55cSDimitry Andric DCHECK_EQ(heap_size % kHeapAlignment, 0);
72349cc55cSDimitry Andric DCHECK_LT(heap_begin, heap_begin + heap_size);
7368d75effSDimitry Andric jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
7468d75effSDimitry Andric }
7568d75effSDimitry Andric
__tsan_java_fini()7668d75effSDimitry Andric int __tsan_java_fini() {
77349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_fini);
7868d75effSDimitry Andric DPrintf("#%d: java_fini()\n", thr->tid);
79349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
8068d75effSDimitry Andric // FIXME(dvyukov): this does not call atexit() callbacks.
8168d75effSDimitry Andric int status = Finalize(thr);
8268d75effSDimitry Andric DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
8368d75effSDimitry Andric return status;
8468d75effSDimitry Andric }
8568d75effSDimitry Andric
__tsan_java_alloc(jptr ptr,jptr size)8668d75effSDimitry Andric void __tsan_java_alloc(jptr ptr, jptr size) {
87349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_alloc);
88349cc55cSDimitry Andric DPrintf("#%d: java_alloc(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
89349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
90349cc55cSDimitry Andric DCHECK_NE(size, 0);
91349cc55cSDimitry Andric DCHECK_EQ(ptr % kHeapAlignment, 0);
92349cc55cSDimitry Andric DCHECK_EQ(size % kHeapAlignment, 0);
93349cc55cSDimitry Andric DCHECK_GE(ptr, jctx->heap_begin);
94349cc55cSDimitry Andric DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
9568d75effSDimitry Andric
96349cc55cSDimitry Andric OnUserAlloc(thr, 0, ptr, size, false);
9768d75effSDimitry Andric }
9868d75effSDimitry Andric
__tsan_java_free(jptr ptr,jptr size)9968d75effSDimitry Andric void __tsan_java_free(jptr ptr, jptr size) {
100349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_free);
101349cc55cSDimitry Andric DPrintf("#%d: java_free(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
102349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
103349cc55cSDimitry Andric DCHECK_NE(size, 0);
104349cc55cSDimitry Andric DCHECK_EQ(ptr % kHeapAlignment, 0);
105349cc55cSDimitry Andric DCHECK_EQ(size % kHeapAlignment, 0);
106349cc55cSDimitry Andric DCHECK_GE(ptr, jctx->heap_begin);
107349cc55cSDimitry Andric DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
10868d75effSDimitry Andric
109*0eae32dcSDimitry Andric ctx->metamap.FreeRange(thr->proc(), ptr, size, false);
11068d75effSDimitry Andric }
11168d75effSDimitry Andric
__tsan_java_move(jptr src,jptr dst,jptr size)11268d75effSDimitry Andric void __tsan_java_move(jptr src, jptr dst, jptr size) {
113349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_move);
114349cc55cSDimitry Andric DPrintf("#%d: java_move(0x%zx, 0x%zx, 0x%zx)\n", thr->tid, src, dst, size);
115349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
116349cc55cSDimitry Andric DCHECK_NE(size, 0);
117349cc55cSDimitry Andric DCHECK_EQ(src % kHeapAlignment, 0);
118349cc55cSDimitry Andric DCHECK_EQ(dst % kHeapAlignment, 0);
119349cc55cSDimitry Andric DCHECK_EQ(size % kHeapAlignment, 0);
120349cc55cSDimitry Andric DCHECK_GE(src, jctx->heap_begin);
121349cc55cSDimitry Andric DCHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
122349cc55cSDimitry Andric DCHECK_GE(dst, jctx->heap_begin);
123349cc55cSDimitry Andric DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
124349cc55cSDimitry Andric DCHECK_NE(dst, src);
125349cc55cSDimitry Andric DCHECK_NE(size, 0);
12668d75effSDimitry Andric
12768d75effSDimitry Andric // Assuming it's not running concurrently with threads that do
12868d75effSDimitry Andric // memory accesses and mutex operations (stop-the-world phase).
12968d75effSDimitry Andric ctx->metamap.MoveMemory(src, dst, size);
13068d75effSDimitry Andric
131349cc55cSDimitry Andric // Clear the destination shadow range.
132349cc55cSDimitry Andric // We used to move shadow from src to dst, but the trace format does not
133349cc55cSDimitry Andric // support that anymore as it contains addresses of accesses.
134349cc55cSDimitry Andric RawShadow *d = MemToShadow(dst);
135349cc55cSDimitry Andric RawShadow *dend = MemToShadow(dst + size);
136*0eae32dcSDimitry Andric ShadowSet(d, dend, Shadow::kEmpty);
13768d75effSDimitry Andric }
13868d75effSDimitry Andric
__tsan_java_find(jptr * from_ptr,jptr to)13968d75effSDimitry Andric jptr __tsan_java_find(jptr *from_ptr, jptr to) {
140349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_find);
141349cc55cSDimitry Andric DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
142349cc55cSDimitry Andric DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
143349cc55cSDimitry Andric DCHECK_EQ(to % kHeapAlignment, 0);
144349cc55cSDimitry Andric DCHECK_GE(*from_ptr, jctx->heap_begin);
145349cc55cSDimitry Andric DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
14668d75effSDimitry Andric for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
14768d75effSDimitry Andric MBlock *b = ctx->metamap.GetBlock(from);
14868d75effSDimitry Andric if (b) {
14968d75effSDimitry Andric *from_ptr = from;
15068d75effSDimitry Andric return b->siz;
15168d75effSDimitry Andric }
15268d75effSDimitry Andric }
15368d75effSDimitry Andric return 0;
15468d75effSDimitry Andric }
15568d75effSDimitry Andric
__tsan_java_finalize()15668d75effSDimitry Andric void __tsan_java_finalize() {
157349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_finalize);
158349cc55cSDimitry Andric DPrintf("#%d: java_finalize()\n", thr->tid);
159349cc55cSDimitry Andric AcquireGlobal(thr);
16068d75effSDimitry Andric }
16168d75effSDimitry Andric
__tsan_java_mutex_lock(jptr addr)16268d75effSDimitry Andric void __tsan_java_mutex_lock(jptr addr) {
163349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
164349cc55cSDimitry Andric DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
165349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
166349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
167349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
16868d75effSDimitry Andric
169349cc55cSDimitry Andric MutexPostLock(thr, 0, addr,
170349cc55cSDimitry Andric MutexFlagLinkerInit | MutexFlagWriteReentrant |
17168d75effSDimitry Andric MutexFlagDoPreLockOnPostLock);
17268d75effSDimitry Andric }
17368d75effSDimitry Andric
__tsan_java_mutex_unlock(jptr addr)17468d75effSDimitry Andric void __tsan_java_mutex_unlock(jptr addr) {
175349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
176349cc55cSDimitry Andric DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
177349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
178349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
179349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
18068d75effSDimitry Andric
181349cc55cSDimitry Andric MutexUnlock(thr, 0, addr);
18268d75effSDimitry Andric }
18368d75effSDimitry Andric
__tsan_java_mutex_read_lock(jptr addr)18468d75effSDimitry Andric void __tsan_java_mutex_read_lock(jptr addr) {
185349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
186349cc55cSDimitry Andric DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
187349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
188349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
189349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
19068d75effSDimitry Andric
191349cc55cSDimitry Andric MutexPostReadLock(thr, 0, addr,
192349cc55cSDimitry Andric MutexFlagLinkerInit | MutexFlagWriteReentrant |
193349cc55cSDimitry Andric MutexFlagDoPreLockOnPostLock);
19468d75effSDimitry Andric }
19568d75effSDimitry Andric
__tsan_java_mutex_read_unlock(jptr addr)19668d75effSDimitry Andric void __tsan_java_mutex_read_unlock(jptr addr) {
197349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
198349cc55cSDimitry Andric DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
199349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
200349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
201349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
20268d75effSDimitry Andric
203349cc55cSDimitry Andric MutexReadUnlock(thr, 0, addr);
20468d75effSDimitry Andric }
20568d75effSDimitry Andric
__tsan_java_mutex_lock_rec(jptr addr,int rec)20668d75effSDimitry Andric void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
207349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
208349cc55cSDimitry Andric DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
209349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
210349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
211349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
212349cc55cSDimitry Andric DCHECK_GT(rec, 0);
21368d75effSDimitry Andric
214349cc55cSDimitry Andric MutexPostLock(thr, 0, addr,
215349cc55cSDimitry Andric MutexFlagLinkerInit | MutexFlagWriteReentrant |
216349cc55cSDimitry Andric MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
217349cc55cSDimitry Andric rec);
21868d75effSDimitry Andric }
21968d75effSDimitry Andric
__tsan_java_mutex_unlock_rec(jptr addr)22068d75effSDimitry Andric int __tsan_java_mutex_unlock_rec(jptr addr) {
221349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
222349cc55cSDimitry Andric DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
223349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
224349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
225349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
22668d75effSDimitry Andric
227349cc55cSDimitry Andric return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
22868d75effSDimitry Andric }
22968d75effSDimitry Andric
__tsan_java_acquire(jptr addr)23068d75effSDimitry Andric void __tsan_java_acquire(jptr addr) {
231349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_acquire);
232349cc55cSDimitry Andric DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
233349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
234349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
235349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
23668d75effSDimitry Andric
237349cc55cSDimitry Andric Acquire(thr, 0, addr);
23868d75effSDimitry Andric }
23968d75effSDimitry Andric
__tsan_java_release(jptr addr)24068d75effSDimitry Andric void __tsan_java_release(jptr addr) {
241349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_release);
242349cc55cSDimitry Andric DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
243349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
244349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
245349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
24668d75effSDimitry Andric
247349cc55cSDimitry Andric Release(thr, 0, addr);
24868d75effSDimitry Andric }
24968d75effSDimitry Andric
__tsan_java_release_store(jptr addr)25068d75effSDimitry Andric void __tsan_java_release_store(jptr addr) {
251349cc55cSDimitry Andric JAVA_FUNC_ENTER(__tsan_java_release);
252349cc55cSDimitry Andric DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
253349cc55cSDimitry Andric DCHECK_NE(jctx, 0);
254349cc55cSDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
255349cc55cSDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
25668d75effSDimitry Andric
257349cc55cSDimitry Andric ReleaseStore(thr, 0, addr);
25868d75effSDimitry Andric }
259