xref: /llvm-project/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp (revision 6563bb53b5fd837a2a0368c58de1cf02ec921d27)
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(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 SCOPED_JAVA_FUNC(func)     \
60   ThreadState *thr = cur_thread(); \
61   (void)thr;                       \
62   /**/
63 
64 void __tsan_java_init(jptr heap_begin, jptr heap_size) {
65   SCOPED_JAVA_FUNC(__tsan_java_init);
66   DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
67   CHECK_EQ(jctx, 0);
68   CHECK_GT(heap_begin, 0);
69   CHECK_GT(heap_size, 0);
70   CHECK_EQ(heap_begin % kHeapAlignment, 0);
71   CHECK_EQ(heap_size % kHeapAlignment, 0);
72   CHECK_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   SCOPED_JAVA_FUNC(__tsan_java_fini);
78   DPrintf("#%d: java_fini()\n", thr->tid);
79   CHECK_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   SCOPED_JAVA_FUNC(__tsan_java_alloc);
88   DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
89   CHECK_NE(jctx, 0);
90   CHECK_NE(size, 0);
91   CHECK_EQ(ptr % kHeapAlignment, 0);
92   CHECK_EQ(size % kHeapAlignment, 0);
93   CHECK_GE(ptr, jctx->heap_begin);
94   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
95 
96   OnUserAlloc(thr, 0, ptr, size, false);
97 }
98 
99 void __tsan_java_free(jptr ptr, jptr size) {
100   SCOPED_JAVA_FUNC(__tsan_java_free);
101   DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
102   CHECK_NE(jctx, 0);
103   CHECK_NE(size, 0);
104   CHECK_EQ(ptr % kHeapAlignment, 0);
105   CHECK_EQ(size % kHeapAlignment, 0);
106   CHECK_GE(ptr, jctx->heap_begin);
107   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
108 
109   ctx->metamap.FreeRange(thr->proc(), ptr, size);
110 }
111 
112 void __tsan_java_move(jptr src, jptr dst, jptr size) {
113   SCOPED_JAVA_FUNC(__tsan_java_move);
114   DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
115   CHECK_NE(jctx, 0);
116   CHECK_NE(size, 0);
117   CHECK_EQ(src % kHeapAlignment, 0);
118   CHECK_EQ(dst % kHeapAlignment, 0);
119   CHECK_EQ(size % kHeapAlignment, 0);
120   CHECK_GE(src, jctx->heap_begin);
121   CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
122   CHECK_GE(dst, jctx->heap_begin);
123   CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
124   CHECK_NE(dst, src);
125   CHECK_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   // Move shadow.
132   u64 *s = (u64*)MemToShadow(src);
133   u64 *d = (u64*)MemToShadow(dst);
134   u64 *send = (u64*)MemToShadow(src + size);
135   uptr inc = 1;
136   if (dst > src) {
137     s = (u64*)MemToShadow(src + size) - 1;
138     d = (u64*)MemToShadow(dst + size) - 1;
139     send = (u64*)MemToShadow(src) - 1;
140     inc = -1;
141   }
142   for (; s != send; s += inc, d += inc) {
143     *d = *s;
144     *s = 0;
145   }
146 }
147 
148 jptr __tsan_java_find(jptr *from_ptr, jptr to) {
149   SCOPED_JAVA_FUNC(__tsan_java_find);
150   DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to);
151   CHECK_EQ((*from_ptr) % kHeapAlignment, 0);
152   CHECK_EQ(to % kHeapAlignment, 0);
153   CHECK_GE(*from_ptr, jctx->heap_begin);
154   CHECK_LE(to, jctx->heap_begin + jctx->heap_size);
155   for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
156     MBlock *b = ctx->metamap.GetBlock(from);
157     if (b) {
158       *from_ptr = from;
159       return b->siz;
160     }
161   }
162   return 0;
163 }
164 
165 void __tsan_java_finalize() {
166   SCOPED_JAVA_FUNC(__tsan_java_finalize);
167   DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
168   AcquireGlobal(thr);
169 }
170 
171 void __tsan_java_mutex_lock(jptr addr) {
172   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
173   DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
174   CHECK_NE(jctx, 0);
175   CHECK_GE(addr, jctx->heap_begin);
176   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
177 
178   MutexPostLock(thr, 0, addr,
179                 MutexFlagLinkerInit | MutexFlagWriteReentrant |
180                     MutexFlagDoPreLockOnPostLock);
181 }
182 
183 void __tsan_java_mutex_unlock(jptr addr) {
184   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
185   DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
186   CHECK_NE(jctx, 0);
187   CHECK_GE(addr, jctx->heap_begin);
188   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
189 
190   MutexUnlock(thr, 0, addr);
191 }
192 
193 void __tsan_java_mutex_read_lock(jptr addr) {
194   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
195   DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
196   CHECK_NE(jctx, 0);
197   CHECK_GE(addr, jctx->heap_begin);
198   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
199 
200   MutexPostReadLock(thr, 0, addr,
201                     MutexFlagLinkerInit | MutexFlagWriteReentrant |
202                         MutexFlagDoPreLockOnPostLock);
203 }
204 
205 void __tsan_java_mutex_read_unlock(jptr addr) {
206   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
207   DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
208   CHECK_NE(jctx, 0);
209   CHECK_GE(addr, jctx->heap_begin);
210   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
211 
212   MutexReadUnlock(thr, 0, addr);
213 }
214 
215 void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
216   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
217   DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
218   CHECK_NE(jctx, 0);
219   CHECK_GE(addr, jctx->heap_begin);
220   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
221   CHECK_GT(rec, 0);
222 
223   MutexPostLock(thr, 0, addr,
224                 MutexFlagLinkerInit | MutexFlagWriteReentrant |
225                     MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
226                 rec);
227 }
228 
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, 0, addr, MutexFlagRecursiveUnlock);
237 }
238 
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, 0, addr);
247 }
248 
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, 0, addr);
257 }
258 
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, 0, addr);
267 }
268