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 | |
21 | using namespace __tsan; |
22 | |
23 | const jptr kHeapAlignment = 8; |
24 | |
25 | namespace __tsan { |
26 | |
27 | struct 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 | |
37 | static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; |
38 | static JavaContext *jctx; |
39 | |
40 | MBlock *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 | |
63 | void __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 | |
76 | int __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 | |
86 | void __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 | |
99 | void __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 | |
112 | void __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 | |
139 | jptr __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 | |
156 | void __tsan_java_finalize() { |
157 | JAVA_FUNC_ENTER(__tsan_java_finalize); |
158 | DPrintf("#%d: java_finalize()\n" , thr->tid); |
159 | AcquireGlobal(thr); |
160 | } |
161 | |
162 | void __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 | |
174 | void __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 | |
184 | void __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 | |
196 | void __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 | |
206 | void __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 | |
220 | int __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 | |
230 | void __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 | |
240 | void __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 | |
250 | void __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 | |