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