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
JavaContext__tsan::JavaContext31 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
JavaHeapBlock(uptr addr,uptr * start)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(addr, 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
__tsan_java_init(jptr heap_begin,jptr heap_size)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
__tsan_java_fini()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
__tsan_java_alloc(jptr ptr,jptr size)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, 0, ptr, size, false);
97 }
98
__tsan_java_free(jptr ptr,jptr size)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(thr->proc(), ptr, size, false);
110 }
111
__tsan_java_move(jptr src,jptr dst,jptr size)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, 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(dst);
135 RawShadow *dend = MemToShadow(dst + size);
136 ShadowSet(d, dend, Shadow::kEmpty);
137 }
138
__tsan_java_find(jptr * from_ptr,jptr to)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(from);
148 if (b) {
149 *from_ptr = from;
150 return b->siz;
151 }
152 }
153 return 0;
154 }
155
__tsan_java_finalize()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
__tsan_java_mutex_lock(jptr addr)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, 0, addr,
170 MutexFlagLinkerInit | MutexFlagWriteReentrant |
171 MutexFlagDoPreLockOnPostLock);
172 }
173
__tsan_java_mutex_unlock(jptr addr)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, 0, addr);
182 }
183
__tsan_java_mutex_read_lock(jptr addr)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, 0, addr,
192 MutexFlagLinkerInit | MutexFlagWriteReentrant |
193 MutexFlagDoPreLockOnPostLock);
194 }
195
__tsan_java_mutex_read_unlock(jptr addr)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, 0, addr);
204 }
205
__tsan_java_mutex_lock_rec(jptr addr,int rec)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, 0, addr,
215 MutexFlagLinkerInit | MutexFlagWriteReentrant |
216 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
217 rec);
218 }
219
__tsan_java_mutex_unlock_rec(jptr addr)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, 0, addr, MutexFlagRecursiveUnlock);
228 }
229
__tsan_java_acquire(jptr addr)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, 0, addr);
238 }
239
__tsan_java_release(jptr addr)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, 0, addr);
248 }
249
__tsan_java_release_store(jptr addr)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, 0, addr);
258 }
259