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 "tsan_mutex.h"
16 #include "sanitizer_common/sanitizer_internal_defs.h"
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_placement_new.h"
19 #include "sanitizer_common/sanitizer_stacktrace.h"
20 #include "sanitizer_common/sanitizer_procmaps.h"
21
22 using namespace __tsan;
23
24 const jptr kHeapAlignment = 8;
25
26 namespace __tsan {
27
28 struct JavaContext {
29 const uptr heap_begin;
30 const uptr heap_size;
31
JavaContext__tsan::JavaContext32 JavaContext(jptr heap_begin, jptr heap_size)
33 : heap_begin(heap_begin)
34 , heap_size(heap_size) {
35 }
36 };
37
38 class ScopedJavaFunc {
39 public:
ScopedJavaFunc(ThreadState * thr,uptr pc)40 ScopedJavaFunc(ThreadState *thr, uptr pc)
41 : thr_(thr) {
42 Initialize(thr_);
43 FuncEntry(thr, pc);
44 }
45
~ScopedJavaFunc()46 ~ScopedJavaFunc() {
47 FuncExit(thr_);
48 // FIXME(dvyukov): process pending signals.
49 }
50
51 private:
52 ThreadState *thr_;
53 };
54
55 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
56 static JavaContext *jctx;
57
58 } // namespace __tsan
59
60 #define SCOPED_JAVA_FUNC(func) \
61 ThreadState *thr = cur_thread(); \
62 const uptr caller_pc = GET_CALLER_PC(); \
63 const uptr pc = StackTrace::GetCurrentPc(); \
64 (void)pc; \
65 ScopedJavaFunc scoped(thr, caller_pc); \
66 /**/
67
__tsan_java_init(jptr heap_begin,jptr heap_size)68 void __tsan_java_init(jptr heap_begin, jptr heap_size) {
69 SCOPED_JAVA_FUNC(__tsan_java_init);
70 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
71 CHECK_EQ(jctx, 0);
72 CHECK_GT(heap_begin, 0);
73 CHECK_GT(heap_size, 0);
74 CHECK_EQ(heap_begin % kHeapAlignment, 0);
75 CHECK_EQ(heap_size % kHeapAlignment, 0);
76 CHECK_LT(heap_begin, heap_begin + heap_size);
77 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
78 }
79
__tsan_java_fini()80 int __tsan_java_fini() {
81 SCOPED_JAVA_FUNC(__tsan_java_fini);
82 DPrintf("#%d: java_fini()\n", thr->tid);
83 CHECK_NE(jctx, 0);
84 // FIXME(dvyukov): this does not call atexit() callbacks.
85 int status = Finalize(thr);
86 DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
87 return status;
88 }
89
__tsan_java_alloc(jptr ptr,jptr size)90 void __tsan_java_alloc(jptr ptr, jptr size) {
91 SCOPED_JAVA_FUNC(__tsan_java_alloc);
92 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
93 CHECK_NE(jctx, 0);
94 CHECK_NE(size, 0);
95 CHECK_EQ(ptr % kHeapAlignment, 0);
96 CHECK_EQ(size % kHeapAlignment, 0);
97 CHECK_GE(ptr, jctx->heap_begin);
98 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
99
100 OnUserAlloc(thr, pc, ptr, size, false);
101 }
102
__tsan_java_free(jptr ptr,jptr size)103 void __tsan_java_free(jptr ptr, jptr size) {
104 SCOPED_JAVA_FUNC(__tsan_java_free);
105 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
106 CHECK_NE(jctx, 0);
107 CHECK_NE(size, 0);
108 CHECK_EQ(ptr % kHeapAlignment, 0);
109 CHECK_EQ(size % kHeapAlignment, 0);
110 CHECK_GE(ptr, jctx->heap_begin);
111 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
112
113 ctx->metamap.FreeRange(thr->proc(), ptr, size);
114 }
115
__tsan_java_move(jptr src,jptr dst,jptr size)116 void __tsan_java_move(jptr src, jptr dst, jptr size) {
117 SCOPED_JAVA_FUNC(__tsan_java_move);
118 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
119 CHECK_NE(jctx, 0);
120 CHECK_NE(size, 0);
121 CHECK_EQ(src % kHeapAlignment, 0);
122 CHECK_EQ(dst % kHeapAlignment, 0);
123 CHECK_EQ(size % kHeapAlignment, 0);
124 CHECK_GE(src, jctx->heap_begin);
125 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
126 CHECK_GE(dst, jctx->heap_begin);
127 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
128 CHECK_NE(dst, src);
129 CHECK_NE(size, 0);
130
131 // Assuming it's not running concurrently with threads that do
132 // memory accesses and mutex operations (stop-the-world phase).
133 ctx->metamap.MoveMemory(src, dst, size);
134
135 // Move shadow.
136 u64 *s = (u64*)MemToShadow(src);
137 u64 *d = (u64*)MemToShadow(dst);
138 u64 *send = (u64*)MemToShadow(src + size);
139 uptr inc = 1;
140 if (dst > src) {
141 s = (u64*)MemToShadow(src + size) - 1;
142 d = (u64*)MemToShadow(dst + size) - 1;
143 send = (u64*)MemToShadow(src) - 1;
144 inc = -1;
145 }
146 for (; s != send; s += inc, d += inc) {
147 *d = *s;
148 *s = 0;
149 }
150 }
151
__tsan_java_find(jptr * from_ptr,jptr to)152 jptr __tsan_java_find(jptr *from_ptr, jptr to) {
153 SCOPED_JAVA_FUNC(__tsan_java_find);
154 DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to);
155 CHECK_EQ((*from_ptr) % kHeapAlignment, 0);
156 CHECK_EQ(to % kHeapAlignment, 0);
157 CHECK_GE(*from_ptr, jctx->heap_begin);
158 CHECK_LE(to, jctx->heap_begin + jctx->heap_size);
159 for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
160 MBlock *b = ctx->metamap.GetBlock(from);
161 if (b) {
162 *from_ptr = from;
163 return b->siz;
164 }
165 }
166 return 0;
167 }
168
__tsan_java_finalize()169 void __tsan_java_finalize() {
170 SCOPED_JAVA_FUNC(__tsan_java_finalize);
171 DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
172 AcquireGlobal(thr, 0);
173 }
174
__tsan_java_mutex_lock(jptr addr)175 void __tsan_java_mutex_lock(jptr addr) {
176 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
177 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
178 CHECK_NE(jctx, 0);
179 CHECK_GE(addr, jctx->heap_begin);
180 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
181
182 MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
183 MutexFlagDoPreLockOnPostLock);
184 }
185
__tsan_java_mutex_unlock(jptr addr)186 void __tsan_java_mutex_unlock(jptr addr) {
187 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
188 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
189 CHECK_NE(jctx, 0);
190 CHECK_GE(addr, jctx->heap_begin);
191 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
192
193 MutexUnlock(thr, pc, addr);
194 }
195
__tsan_java_mutex_read_lock(jptr addr)196 void __tsan_java_mutex_read_lock(jptr addr) {
197 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
198 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
199 CHECK_NE(jctx, 0);
200 CHECK_GE(addr, jctx->heap_begin);
201 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
202
203 MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit |
204 MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock);
205 }
206
__tsan_java_mutex_read_unlock(jptr addr)207 void __tsan_java_mutex_read_unlock(jptr addr) {
208 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
209 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
210 CHECK_NE(jctx, 0);
211 CHECK_GE(addr, jctx->heap_begin);
212 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
213
214 MutexReadUnlock(thr, pc, addr);
215 }
216
__tsan_java_mutex_lock_rec(jptr addr,int rec)217 void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
218 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
219 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
220 CHECK_NE(jctx, 0);
221 CHECK_GE(addr, jctx->heap_begin);
222 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
223 CHECK_GT(rec, 0);
224
225 MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
226 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec);
227 }
228
__tsan_java_mutex_unlock_rec(jptr addr)229 int __tsan_java_mutex_unlock_rec(jptr addr) {
230 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
231 DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
232 CHECK_NE(jctx, 0);
233 CHECK_GE(addr, jctx->heap_begin);
234 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
235
236 return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock);
237 }
238
__tsan_java_acquire(jptr addr)239 void __tsan_java_acquire(jptr addr) {
240 SCOPED_JAVA_FUNC(__tsan_java_acquire);
241 DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr);
242 CHECK_NE(jctx, 0);
243 CHECK_GE(addr, jctx->heap_begin);
244 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
245
246 Acquire(thr, caller_pc, addr);
247 }
248
__tsan_java_release(jptr addr)249 void __tsan_java_release(jptr addr) {
250 SCOPED_JAVA_FUNC(__tsan_java_release);
251 DPrintf("#%d: java_release(%p)\n", thr->tid, addr);
252 CHECK_NE(jctx, 0);
253 CHECK_GE(addr, jctx->heap_begin);
254 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
255
256 Release(thr, caller_pc, addr);
257 }
258
__tsan_java_release_store(jptr addr)259 void __tsan_java_release_store(jptr addr) {
260 SCOPED_JAVA_FUNC(__tsan_java_release);
261 DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr);
262 CHECK_NE(jctx, 0);
263 CHECK_GE(addr, jctx->heap_begin);
264 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
265
266 ReleaseStore(thr, caller_pc, addr);
267 }
268