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