xref: /llvm-project/compiler-rt/lib/tsan/rtl/tsan_interface_java.cpp (revision a1a37ddc3f0e4d4002b0661e4870b1e949fd5d81)
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 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   DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
66   CHECK_EQ(jctx, 0);
67   CHECK_GT(heap_begin, 0);
68   CHECK_GT(heap_size, 0);
69   CHECK_EQ(heap_begin % kHeapAlignment, 0);
70   CHECK_EQ(heap_size % kHeapAlignment, 0);
71   CHECK_LT(heap_begin, heap_begin + heap_size);
72   jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
73 }
74 
75 int  __tsan_java_fini() {
76   JAVA_FUNC_ENTER(__tsan_java_fini);
77   DPrintf("#%d: java_fini()\n", thr->tid);
78   CHECK_NE(jctx, 0);
79   // FIXME(dvyukov): this does not call atexit() callbacks.
80   int status = Finalize(thr);
81   DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
82   return status;
83 }
84 
85 void __tsan_java_alloc(jptr ptr, jptr size) {
86   JAVA_FUNC_ENTER(__tsan_java_alloc);
87   DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
88   CHECK_NE(jctx, 0);
89   CHECK_NE(size, 0);
90   CHECK_EQ(ptr % kHeapAlignment, 0);
91   CHECK_EQ(size % kHeapAlignment, 0);
92   CHECK_GE(ptr, jctx->heap_begin);
93   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
94 
95   OnUserAlloc(thr, 0, ptr, size, false);
96 }
97 
98 void __tsan_java_free(jptr ptr, jptr size) {
99   JAVA_FUNC_ENTER(__tsan_java_free);
100   DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
101   CHECK_NE(jctx, 0);
102   CHECK_NE(size, 0);
103   CHECK_EQ(ptr % kHeapAlignment, 0);
104   CHECK_EQ(size % kHeapAlignment, 0);
105   CHECK_GE(ptr, jctx->heap_begin);
106   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
107 
108   ctx->metamap.FreeRange(thr->proc(), ptr, size);
109 }
110 
111 void __tsan_java_move(jptr src, jptr dst, jptr size) {
112   JAVA_FUNC_ENTER(__tsan_java_move);
113   DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
114   CHECK_NE(jctx, 0);
115   CHECK_NE(size, 0);
116   CHECK_EQ(src % kHeapAlignment, 0);
117   CHECK_EQ(dst % kHeapAlignment, 0);
118   CHECK_EQ(size % kHeapAlignment, 0);
119   CHECK_GE(src, jctx->heap_begin);
120   CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
121   CHECK_GE(dst, jctx->heap_begin);
122   CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
123   CHECK_NE(dst, src);
124   CHECK_NE(size, 0);
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   // Move shadow.
131   u64 *s = (u64*)MemToShadow(src);
132   u64 *d = (u64*)MemToShadow(dst);
133   u64 *send = (u64*)MemToShadow(src + size);
134   uptr inc = 1;
135   if (dst > src) {
136     s = (u64*)MemToShadow(src + size) - 1;
137     d = (u64*)MemToShadow(dst + size) - 1;
138     send = (u64*)MemToShadow(src) - 1;
139     inc = -1;
140   }
141   for (; s != send; s += inc, d += inc) {
142     *d = *s;
143     *s = 0;
144   }
145 }
146 
147 jptr __tsan_java_find(jptr *from_ptr, jptr to) {
148   JAVA_FUNC_ENTER(__tsan_java_find);
149   DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to);
150   CHECK_EQ((*from_ptr) % kHeapAlignment, 0);
151   CHECK_EQ(to % kHeapAlignment, 0);
152   CHECK_GE(*from_ptr, jctx->heap_begin);
153   CHECK_LE(to, jctx->heap_begin + jctx->heap_size);
154   for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
155     MBlock *b = ctx->metamap.GetBlock(from);
156     if (b) {
157       *from_ptr = from;
158       return b->siz;
159     }
160   }
161   return 0;
162 }
163 
164 void __tsan_java_finalize() {
165   JAVA_FUNC_ENTER(__tsan_java_finalize);
166   DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
167   AcquireGlobal(thr);
168 }
169 
170 void __tsan_java_mutex_lock(jptr addr) {
171   JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
172   DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
173   CHECK_NE(jctx, 0);
174   CHECK_GE(addr, jctx->heap_begin);
175   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
176 
177   MutexPostLock(thr, 0, addr,
178                 MutexFlagLinkerInit | MutexFlagWriteReentrant |
179                     MutexFlagDoPreLockOnPostLock);
180 }
181 
182 void __tsan_java_mutex_unlock(jptr addr) {
183   JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
184   DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
185   CHECK_NE(jctx, 0);
186   CHECK_GE(addr, jctx->heap_begin);
187   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
188 
189   MutexUnlock(thr, 0, addr);
190 }
191 
192 void __tsan_java_mutex_read_lock(jptr addr) {
193   JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
194   DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
195   CHECK_NE(jctx, 0);
196   CHECK_GE(addr, jctx->heap_begin);
197   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
198 
199   MutexPostReadLock(thr, 0, addr,
200                     MutexFlagLinkerInit | MutexFlagWriteReentrant |
201                         MutexFlagDoPreLockOnPostLock);
202 }
203 
204 void __tsan_java_mutex_read_unlock(jptr addr) {
205   JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
206   DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
207   CHECK_NE(jctx, 0);
208   CHECK_GE(addr, jctx->heap_begin);
209   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
210 
211   MutexReadUnlock(thr, 0, addr);
212 }
213 
214 void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
215   JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
216   DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
217   CHECK_NE(jctx, 0);
218   CHECK_GE(addr, jctx->heap_begin);
219   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
220   CHECK_GT(rec, 0);
221 
222   MutexPostLock(thr, 0, addr,
223                 MutexFlagLinkerInit | MutexFlagWriteReentrant |
224                     MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
225                 rec);
226 }
227 
228 int __tsan_java_mutex_unlock_rec(jptr addr) {
229   JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
230   DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
231   CHECK_NE(jctx, 0);
232   CHECK_GE(addr, jctx->heap_begin);
233   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
234 
235   return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
236 }
237 
238 void __tsan_java_acquire(jptr addr) {
239   JAVA_FUNC_ENTER(__tsan_java_acquire);
240   DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr);
241   CHECK_NE(jctx, 0);
242   CHECK_GE(addr, jctx->heap_begin);
243   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
244 
245   Acquire(thr, 0, addr);
246 }
247 
248 void __tsan_java_release(jptr addr) {
249   JAVA_FUNC_ENTER(__tsan_java_release);
250   DPrintf("#%d: java_release(%p)\n", thr->tid, addr);
251   CHECK_NE(jctx, 0);
252   CHECK_GE(addr, jctx->heap_begin);
253   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
254 
255   Release(thr, 0, addr);
256 }
257 
258 void __tsan_java_release_store(jptr addr) {
259   JAVA_FUNC_ENTER(__tsan_java_release);
260   DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr);
261   CHECK_NE(jctx, 0);
262   CHECK_GE(addr, jctx->heap_begin);
263   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
264 
265   ReleaseStore(thr, 0, addr);
266 }
267