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
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, 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(dst);
134 RawShadow *dend = MemToShadow(dst + size);
135 ShadowSet(d, dend, Shadow::kEmpty);
136 }
137
__tsan_java_find(jptr * from_ptr,jptr to)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(from);
147 if (b) {
148 *from_ptr = from;
149 return b->siz;
150 }
151 }
152 return 0;
153 }
154
__tsan_java_finalize()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
__tsan_java_mutex_lock(jptr addr)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, 0, addr,
169 MutexFlagLinkerInit | MutexFlagWriteReentrant |
170 MutexFlagDoPreLockOnPostLock);
171 }
172
__tsan_java_mutex_unlock(jptr addr)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, 0, addr);
181 }
182
__tsan_java_mutex_read_lock(jptr addr)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, 0, addr,
191 MutexFlagLinkerInit | MutexFlagWriteReentrant |
192 MutexFlagDoPreLockOnPostLock);
193 }
194
__tsan_java_mutex_read_unlock(jptr addr)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, 0, addr);
203 }
204
__tsan_java_mutex_lock_rec(jptr addr,int rec)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, 0, addr,
214 MutexFlagLinkerInit | MutexFlagWriteReentrant |
215 MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
216 rec);
217 }
218
__tsan_java_mutex_unlock_rec(jptr addr)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, 0, addr, MutexFlagRecursiveUnlock);
227 }
228
__tsan_java_acquire(jptr addr)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, 0, addr);
237 }
238
__tsan_java_release(jptr addr)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, 0, addr);
247 }
248
__tsan_java_release_store(jptr addr)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, 0, addr);
257 }
258