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 | |
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 | |
138 | jptr __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 | |
155 | void __tsan_java_finalize() { |
156 | JAVA_FUNC_ENTER(__tsan_java_finalize); |
157 | DPrintf("#%d: java_finalize()\n" , thr->tid); |
158 | AcquireGlobal(thr); |
159 | } |
160 | |
161 | void __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 | |
173 | void __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 | |
183 | void __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 | |
195 | void __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 | |
205 | void __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 | |
219 | int __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 | |
229 | void __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 | |
239 | void __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 | |
249 | void __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 | |