13a1720afSDimitry Andric //===-- tsan_interface_java.cpp -------------------------------------------===//
258aabf08SAndrew Turner //
38f3cadc2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48f3cadc2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58f3cadc2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
658aabf08SAndrew Turner //
758aabf08SAndrew Turner //===----------------------------------------------------------------------===//
858aabf08SAndrew Turner //
958aabf08SAndrew Turner // This file is a part of ThreadSanitizer (TSan), a race detector.
1058aabf08SAndrew Turner //
1158aabf08SAndrew Turner //===----------------------------------------------------------------------===//
1258aabf08SAndrew Turner
1358aabf08SAndrew Turner #include "tsan_interface_java.h"
1458aabf08SAndrew Turner #include "tsan_rtl.h"
1558aabf08SAndrew Turner #include "sanitizer_common/sanitizer_internal_defs.h"
1658aabf08SAndrew Turner #include "sanitizer_common/sanitizer_common.h"
1758aabf08SAndrew Turner #include "sanitizer_common/sanitizer_placement_new.h"
188ef50bf3SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
198ef50bf3SDimitry Andric #include "sanitizer_common/sanitizer_procmaps.h"
2058aabf08SAndrew Turner
213a1720afSDimitry Andric using namespace __tsan;
2258aabf08SAndrew Turner
23ca9211ecSDimitry Andric const jptr kHeapAlignment = 8;
24ca9211ecSDimitry Andric
2558aabf08SAndrew Turner namespace __tsan {
2658aabf08SAndrew Turner
2758aabf08SAndrew Turner struct JavaContext {
2858aabf08SAndrew Turner const uptr heap_begin;
2958aabf08SAndrew Turner const uptr heap_size;
3058aabf08SAndrew Turner
JavaContext__tsan::JavaContext3158aabf08SAndrew Turner JavaContext(jptr heap_begin, jptr heap_size)
3258aabf08SAndrew Turner : heap_begin(heap_begin)
3358aabf08SAndrew Turner , heap_size(heap_size) {
3458aabf08SAndrew Turner }
3558aabf08SAndrew Turner };
3658aabf08SAndrew Turner
3758aabf08SAndrew Turner static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
3858aabf08SAndrew Turner static JavaContext *jctx;
3958aabf08SAndrew Turner
JavaHeapBlock(uptr addr,uptr * start)40c0981da4SDimitry Andric MBlock *JavaHeapBlock(uptr addr, uptr *start) {
41c0981da4SDimitry Andric if (!jctx || addr < jctx->heap_begin ||
42c0981da4SDimitry Andric addr >= jctx->heap_begin + jctx->heap_size)
43c0981da4SDimitry Andric return nullptr;
44c0981da4SDimitry Andric for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin;
45c0981da4SDimitry Andric p -= kMetaShadowCell) {
46c0981da4SDimitry Andric MBlock *b = ctx->metamap.GetBlock(p);
47c0981da4SDimitry Andric if (!b)
48c0981da4SDimitry Andric continue;
49c0981da4SDimitry Andric if (p + b->siz <= addr)
50c0981da4SDimitry Andric return nullptr;
51c0981da4SDimitry Andric *start = p;
52c0981da4SDimitry Andric return b;
53c0981da4SDimitry Andric }
54c0981da4SDimitry Andric return nullptr;
55c0981da4SDimitry Andric }
56c0981da4SDimitry Andric
5711023dc6SEd Schouten } // namespace __tsan
5858aabf08SAndrew Turner
59c0981da4SDimitry Andric #define JAVA_FUNC_ENTER(func) \
6058aabf08SAndrew Turner ThreadState *thr = cur_thread(); \
61c0981da4SDimitry Andric (void)thr;
6258aabf08SAndrew Turner
__tsan_java_init(jptr heap_begin,jptr heap_size)6358aabf08SAndrew Turner void __tsan_java_init(jptr heap_begin, jptr heap_size) {
64c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_init);
65c0981da4SDimitry Andric Initialize(thr);
66c0981da4SDimitry Andric DPrintf("#%d: java_init(0x%zx, 0x%zx)\n", thr->tid, heap_begin, heap_size);
67c0981da4SDimitry Andric DCHECK_EQ(jctx, 0);
68c0981da4SDimitry Andric DCHECK_GT(heap_begin, 0);
69c0981da4SDimitry Andric DCHECK_GT(heap_size, 0);
70c0981da4SDimitry Andric DCHECK_EQ(heap_begin % kHeapAlignment, 0);
71c0981da4SDimitry Andric DCHECK_EQ(heap_size % kHeapAlignment, 0);
72c0981da4SDimitry Andric DCHECK_LT(heap_begin, heap_begin + heap_size);
7358aabf08SAndrew Turner jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
7458aabf08SAndrew Turner }
7558aabf08SAndrew Turner
__tsan_java_fini()7658aabf08SAndrew Turner int __tsan_java_fini() {
77c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_fini);
7858aabf08SAndrew Turner DPrintf("#%d: java_fini()\n", thr->tid);
79c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
8058aabf08SAndrew Turner // FIXME(dvyukov): this does not call atexit() callbacks.
8158aabf08SAndrew Turner int status = Finalize(thr);
8258aabf08SAndrew Turner DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
8358aabf08SAndrew Turner return status;
8458aabf08SAndrew Turner }
8558aabf08SAndrew Turner
__tsan_java_alloc(jptr ptr,jptr size)8658aabf08SAndrew Turner void __tsan_java_alloc(jptr ptr, jptr size) {
87c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_alloc);
88c0981da4SDimitry Andric DPrintf("#%d: java_alloc(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
89c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
90c0981da4SDimitry Andric DCHECK_NE(size, 0);
91c0981da4SDimitry Andric DCHECK_EQ(ptr % kHeapAlignment, 0);
92c0981da4SDimitry Andric DCHECK_EQ(size % kHeapAlignment, 0);
93c0981da4SDimitry Andric DCHECK_GE(ptr, jctx->heap_begin);
94c0981da4SDimitry Andric DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
9558aabf08SAndrew Turner
96c0981da4SDimitry Andric OnUserAlloc(thr, 0, ptr, size, false);
9758aabf08SAndrew Turner }
9858aabf08SAndrew Turner
__tsan_java_free(jptr ptr,jptr size)9958aabf08SAndrew Turner void __tsan_java_free(jptr ptr, jptr size) {
100c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_free);
101c0981da4SDimitry Andric DPrintf("#%d: java_free(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
102c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
103c0981da4SDimitry Andric DCHECK_NE(size, 0);
104c0981da4SDimitry Andric DCHECK_EQ(ptr % kHeapAlignment, 0);
105c0981da4SDimitry Andric DCHECK_EQ(size % kHeapAlignment, 0);
106c0981da4SDimitry Andric DCHECK_GE(ptr, jctx->heap_begin);
107c0981da4SDimitry Andric DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
10858aabf08SAndrew Turner
10977fc4c14SDimitry Andric ctx->metamap.FreeRange(thr->proc(), ptr, size, false);
11058aabf08SAndrew Turner }
11158aabf08SAndrew Turner
__tsan_java_move(jptr src,jptr dst,jptr size)11258aabf08SAndrew Turner void __tsan_java_move(jptr src, jptr dst, jptr size) {
113c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_move);
114c0981da4SDimitry Andric DPrintf("#%d: java_move(0x%zx, 0x%zx, 0x%zx)\n", thr->tid, src, dst, size);
115c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
116c0981da4SDimitry Andric DCHECK_NE(size, 0);
117c0981da4SDimitry Andric DCHECK_EQ(src % kHeapAlignment, 0);
118c0981da4SDimitry Andric DCHECK_EQ(dst % kHeapAlignment, 0);
119c0981da4SDimitry Andric DCHECK_EQ(size % kHeapAlignment, 0);
120c0981da4SDimitry Andric DCHECK_GE(src, jctx->heap_begin);
121c0981da4SDimitry Andric DCHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
122c0981da4SDimitry Andric DCHECK_GE(dst, jctx->heap_begin);
123c0981da4SDimitry Andric DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
124c0981da4SDimitry Andric DCHECK_NE(dst, src);
125c0981da4SDimitry Andric DCHECK_NE(size, 0);
12658aabf08SAndrew Turner
12758aabf08SAndrew Turner // Assuming it's not running concurrently with threads that do
12858aabf08SAndrew Turner // memory accesses and mutex operations (stop-the-world phase).
129ca9211ecSDimitry Andric ctx->metamap.MoveMemory(src, dst, size);
13058aabf08SAndrew Turner
131c0981da4SDimitry Andric // Clear the destination shadow range.
132c0981da4SDimitry Andric // We used to move shadow from src to dst, but the trace format does not
133c0981da4SDimitry Andric // support that anymore as it contains addresses of accesses.
134c0981da4SDimitry Andric RawShadow *d = MemToShadow(dst);
135c0981da4SDimitry Andric RawShadow *dend = MemToShadow(dst + size);
13677fc4c14SDimitry Andric ShadowSet(d, dend, Shadow::kEmpty);
13758aabf08SAndrew Turner }
138ca9211ecSDimitry Andric
__tsan_java_find(jptr * from_ptr,jptr to)139316d5882SDimitry Andric jptr __tsan_java_find(jptr *from_ptr, jptr to) {
140c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_find);
141c0981da4SDimitry Andric DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
142c0981da4SDimitry Andric DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
143c0981da4SDimitry Andric DCHECK_EQ(to % kHeapAlignment, 0);
144c0981da4SDimitry Andric DCHECK_GE(*from_ptr, jctx->heap_begin);
145c0981da4SDimitry Andric DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
146316d5882SDimitry Andric for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
147316d5882SDimitry Andric MBlock *b = ctx->metamap.GetBlock(from);
148316d5882SDimitry Andric if (b) {
149316d5882SDimitry Andric *from_ptr = from;
150316d5882SDimitry Andric return b->siz;
151316d5882SDimitry Andric }
152316d5882SDimitry Andric }
153316d5882SDimitry Andric return 0;
154316d5882SDimitry Andric }
155316d5882SDimitry Andric
__tsan_java_finalize()156ca9211ecSDimitry Andric void __tsan_java_finalize() {
157c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_finalize);
158c0981da4SDimitry Andric DPrintf("#%d: java_finalize()\n", thr->tid);
159c0981da4SDimitry Andric AcquireGlobal(thr);
16058aabf08SAndrew Turner }
16158aabf08SAndrew Turner
__tsan_java_mutex_lock(jptr addr)16258aabf08SAndrew Turner void __tsan_java_mutex_lock(jptr addr) {
163c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
164c0981da4SDimitry Andric DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
165c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
166c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
167c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
16858aabf08SAndrew Turner
169c0981da4SDimitry Andric MutexPostLock(thr, 0, addr,
170c0981da4SDimitry Andric MutexFlagLinkerInit | MutexFlagWriteReentrant |
171ab0bf875SDimitry Andric MutexFlagDoPreLockOnPostLock);
17258aabf08SAndrew Turner }
17358aabf08SAndrew Turner
__tsan_java_mutex_unlock(jptr addr)17458aabf08SAndrew Turner void __tsan_java_mutex_unlock(jptr addr) {
175c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
176c0981da4SDimitry Andric DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
177c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
178c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
179c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
18058aabf08SAndrew Turner
181c0981da4SDimitry Andric MutexUnlock(thr, 0, addr);
18258aabf08SAndrew Turner }
18358aabf08SAndrew Turner
__tsan_java_mutex_read_lock(jptr addr)18458aabf08SAndrew Turner void __tsan_java_mutex_read_lock(jptr addr) {
185c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
186c0981da4SDimitry Andric DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
187c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
188c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
189c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
19058aabf08SAndrew Turner
191c0981da4SDimitry Andric MutexPostReadLock(thr, 0, addr,
192c0981da4SDimitry Andric MutexFlagLinkerInit | MutexFlagWriteReentrant |
193c0981da4SDimitry Andric MutexFlagDoPreLockOnPostLock);
19458aabf08SAndrew Turner }
19558aabf08SAndrew Turner
__tsan_java_mutex_read_unlock(jptr addr)19658aabf08SAndrew Turner void __tsan_java_mutex_read_unlock(jptr addr) {
197c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
198c0981da4SDimitry Andric DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
199c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
200c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
201c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
20258aabf08SAndrew Turner
203c0981da4SDimitry Andric MutexReadUnlock(thr, 0, addr);
20458aabf08SAndrew Turner }
20511023dc6SEd Schouten
__tsan_java_mutex_lock_rec(jptr addr,int rec)20611023dc6SEd Schouten void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
207c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
208c0981da4SDimitry Andric DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
209c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
210c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
211c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
212c0981da4SDimitry Andric DCHECK_GT(rec, 0);
21311023dc6SEd Schouten
214c0981da4SDimitry Andric MutexPostLock(thr, 0, addr,
215c0981da4SDimitry Andric MutexFlagLinkerInit | MutexFlagWriteReentrant |
216c0981da4SDimitry Andric MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
217c0981da4SDimitry Andric rec);
21811023dc6SEd Schouten }
21911023dc6SEd Schouten
__tsan_java_mutex_unlock_rec(jptr addr)22011023dc6SEd Schouten int __tsan_java_mutex_unlock_rec(jptr addr) {
221c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
222c0981da4SDimitry Andric DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
223c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
224c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
225c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
22611023dc6SEd Schouten
227c0981da4SDimitry Andric return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
22811023dc6SEd Schouten }
229476c4db3SDimitry Andric
__tsan_java_acquire(jptr addr)230476c4db3SDimitry Andric void __tsan_java_acquire(jptr addr) {
231c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_acquire);
232c0981da4SDimitry Andric DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
233c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
234c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
235c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
236476c4db3SDimitry Andric
237c0981da4SDimitry Andric Acquire(thr, 0, addr);
238476c4db3SDimitry Andric }
239476c4db3SDimitry Andric
__tsan_java_release(jptr addr)240476c4db3SDimitry Andric void __tsan_java_release(jptr addr) {
241c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_release);
242c0981da4SDimitry Andric DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
243c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
244c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
245c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
246476c4db3SDimitry Andric
247c0981da4SDimitry Andric Release(thr, 0, addr);
248476c4db3SDimitry Andric }
249476c4db3SDimitry Andric
__tsan_java_release_store(jptr addr)250476c4db3SDimitry Andric void __tsan_java_release_store(jptr addr) {
251c0981da4SDimitry Andric JAVA_FUNC_ENTER(__tsan_java_release);
252c0981da4SDimitry Andric DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
253c0981da4SDimitry Andric DCHECK_NE(jctx, 0);
254c0981da4SDimitry Andric DCHECK_GE(addr, jctx->heap_begin);
255c0981da4SDimitry Andric DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
256476c4db3SDimitry Andric
257c0981da4SDimitry Andric ReleaseStore(thr, 0, addr);
258476c4db3SDimitry Andric }
259