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 DCHECK_NE(size, 0);
126
127 // Assuming it's not running concurrently with threads that do
128 // memory accesses and mutex operations (stop-the-world phase).
129 ctx->metamap.MoveMemory(src, dst, sz: size);
130
131 // Clear the destination shadow range.
132 // We used to move shadow from src to dst, but the trace format does not
133 // support that anymore as it contains addresses of accesses.
134 RawShadow *d = MemToShadow(x: dst);
135 RawShadow *dend = MemToShadow(x: dst + size);
136 ShadowSet(p: d, end: dend, v: Shadow::kEmpty);
137}
138
139jptr __tsan_java_find(jptr *from_ptr, jptr to) {
140 JAVA_FUNC_ENTER(__tsan_java_find);
141 DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
142 DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
143 DCHECK_EQ(to % kHeapAlignment, 0);
144 DCHECK_GE(*from_ptr, jctx->heap_begin);
145 DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
146 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
147 MBlock *b = ctx->metamap.GetBlock(p: from);
148 if (b) {
149 *from_ptr = from;
150 return b->siz;
151 }
152 }
153 return 0;
154}
155
156void __tsan_java_finalize() {
157 JAVA_FUNC_ENTER(__tsan_java_finalize);
158 DPrintf("#%d: java_finalize()\n", thr->tid);
159 AcquireGlobal(thr);
160}
161
162void __tsan_java_mutex_lock(jptr addr) {
163 JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
164 DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
165 DCHECK_NE(jctx, 0);
166 DCHECK_GE(addr, jctx->heap_begin);
167 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
168
169 MutexPostLock(thr, pc: 0, addr,
170 flagz: MutexFlagLinkerInit | MutexFlagWriteReentrant |
171 MutexFlagDoPreLockOnPostLock);
172}
173
174void __tsan_java_mutex_unlock(jptr addr) {
175 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
176 DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
177 DCHECK_NE(jctx, 0);
178 DCHECK_GE(addr, jctx->heap_begin);
179 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
180
181 MutexUnlock(thr, pc: 0, addr);
182}
183
184void __tsan_java_mutex_read_lock(jptr addr) {
185 JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
186 DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
187 DCHECK_NE(jctx, 0);
188 DCHECK_GE(addr, jctx->heap_begin);
189 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
190
191 MutexPostReadLock(thr, pc: 0, addr,
192 flagz: MutexFlagLinkerInit | MutexFlagWriteReentrant |
193 MutexFlagDoPreLockOnPostLock);
194}
195
196void __tsan_java_mutex_read_unlock(jptr addr) {
197 JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
198 DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
199 DCHECK_NE(jctx, 0);
200 DCHECK_GE(addr, jctx->heap_begin);
201 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
202
203 MutexReadUnlock(thr, pc: 0, addr);
204}
205
206void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
207 JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
208 DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
209 DCHECK_NE(jctx, 0);
210 DCHECK_GE(addr, jctx->heap_begin);
211 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
212 DCHECK_GT(rec, 0);
213
214 MutexPostLock(thr, pc: 0, addr,
215 flagz: MutexFlagLinkerInit | MutexFlagWriteReentrant |
216 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
217 rec);
218}
219
220int __tsan_java_mutex_unlock_rec(jptr addr) {
221 JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
222 DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
223 DCHECK_NE(jctx, 0);
224 DCHECK_GE(addr, jctx->heap_begin);
225 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
226
227 return MutexUnlock(thr, pc: 0, addr, flagz: MutexFlagRecursiveUnlock);
228}
229
230void __tsan_java_acquire(jptr addr) {
231 JAVA_FUNC_ENTER(__tsan_java_acquire);
232 DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
233 DCHECK_NE(jctx, 0);
234 DCHECK_GE(addr, jctx->heap_begin);
235 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
236
237 Acquire(thr, pc: 0, addr);
238}
239
240void __tsan_java_release(jptr addr) {
241 JAVA_FUNC_ENTER(__tsan_java_release);
242 DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
243 DCHECK_NE(jctx, 0);
244 DCHECK_GE(addr, jctx->heap_begin);
245 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
246
247 Release(thr, pc: 0, addr);
248}
249
250void __tsan_java_release_store(jptr addr) {
251 JAVA_FUNC_ENTER(__tsan_java_release);
252 DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
253 DCHECK_NE(jctx, 0);
254 DCHECK_GE(addr, jctx->heap_begin);
255 DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
256
257 ReleaseStore(thr, pc: 0, addr);
258}
259