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 MBlock *JavaHeapBlock(uptr addr, uptr *start) {
58   if (!jctx || addr < jctx->heap_begin ||
59       addr >= jctx->heap_begin + jctx->heap_size)
60     return nullptr;
61   for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin;
62        p -= kMetaShadowCell) {
63     MBlock *b = ctx->metamap.GetBlock(p);
64     if (!b)
65       continue;
66     if (p + b->siz <= addr)
67       return nullptr;
68     *start = p;
69     return b;
70   }
71   return nullptr;
72 }
73 
74 }  // namespace __tsan
75 
76 #define SCOPED_JAVA_FUNC(func) \
77   ThreadState *thr = cur_thread(); \
78   const uptr caller_pc = GET_CALLER_PC(); \
79   const uptr pc = StackTrace::GetCurrentPc(); \
80   (void)pc; \
81   ScopedJavaFunc scoped(thr, caller_pc); \
82 /**/
83 
84 void __tsan_java_init(jptr heap_begin, jptr heap_size) {
85   SCOPED_JAVA_FUNC(__tsan_java_init);
86   DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
87   CHECK_EQ(jctx, 0);
88   CHECK_GT(heap_begin, 0);
89   CHECK_GT(heap_size, 0);
90   CHECK_EQ(heap_begin % kHeapAlignment, 0);
91   CHECK_EQ(heap_size % kHeapAlignment, 0);
92   CHECK_LT(heap_begin, heap_begin + heap_size);
93   jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
94 }
95 
96 int  __tsan_java_fini() {
97   SCOPED_JAVA_FUNC(__tsan_java_fini);
98   DPrintf("#%d: java_fini()\n", thr->tid);
99   CHECK_NE(jctx, 0);
100   // FIXME(dvyukov): this does not call atexit() callbacks.
101   int status = Finalize(thr);
102   DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
103   return status;
104 }
105 
106 void __tsan_java_alloc(jptr ptr, jptr size) {
107   SCOPED_JAVA_FUNC(__tsan_java_alloc);
108   DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
109   CHECK_NE(jctx, 0);
110   CHECK_NE(size, 0);
111   CHECK_EQ(ptr % kHeapAlignment, 0);
112   CHECK_EQ(size % kHeapAlignment, 0);
113   CHECK_GE(ptr, jctx->heap_begin);
114   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
115 
116   OnUserAlloc(thr, pc, ptr, size, false);
117 }
118 
119 void __tsan_java_free(jptr ptr, jptr size) {
120   SCOPED_JAVA_FUNC(__tsan_java_free);
121   DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
122   CHECK_NE(jctx, 0);
123   CHECK_NE(size, 0);
124   CHECK_EQ(ptr % kHeapAlignment, 0);
125   CHECK_EQ(size % kHeapAlignment, 0);
126   CHECK_GE(ptr, jctx->heap_begin);
127   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
128 
129   ctx->metamap.FreeRange(thr->proc(), ptr, size);
130 }
131 
132 void __tsan_java_move(jptr src, jptr dst, jptr size) {
133   SCOPED_JAVA_FUNC(__tsan_java_move);
134   DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
135   CHECK_NE(jctx, 0);
136   CHECK_NE(size, 0);
137   CHECK_EQ(src % kHeapAlignment, 0);
138   CHECK_EQ(dst % kHeapAlignment, 0);
139   CHECK_EQ(size % kHeapAlignment, 0);
140   CHECK_GE(src, jctx->heap_begin);
141   CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
142   CHECK_GE(dst, jctx->heap_begin);
143   CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
144   CHECK_NE(dst, src);
145   CHECK_NE(size, 0);
146 
147   // Assuming it's not running concurrently with threads that do
148   // memory accesses and mutex operations (stop-the-world phase).
149   ctx->metamap.MoveMemory(src, dst, size);
150 
151   // Move shadow.
152   u64 *s = (u64*)MemToShadow(src);
153   u64 *d = (u64*)MemToShadow(dst);
154   u64 *send = (u64*)MemToShadow(src + size);
155   uptr inc = 1;
156   if (dst > src) {
157     s = (u64*)MemToShadow(src + size) - 1;
158     d = (u64*)MemToShadow(dst + size) - 1;
159     send = (u64*)MemToShadow(src) - 1;
160     inc = -1;
161   }
162   for (; s != send; s += inc, d += inc) {
163     *d = *s;
164     *s = 0;
165   }
166 }
167 
168 jptr __tsan_java_find(jptr *from_ptr, jptr to) {
169   SCOPED_JAVA_FUNC(__tsan_java_find);
170   DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to);
171   CHECK_EQ((*from_ptr) % kHeapAlignment, 0);
172   CHECK_EQ(to % kHeapAlignment, 0);
173   CHECK_GE(*from_ptr, jctx->heap_begin);
174   CHECK_LE(to, jctx->heap_begin + jctx->heap_size);
175   for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
176     MBlock *b = ctx->metamap.GetBlock(from);
177     if (b) {
178       *from_ptr = from;
179       return b->siz;
180     }
181   }
182   return 0;
183 }
184 
185 void __tsan_java_finalize() {
186   SCOPED_JAVA_FUNC(__tsan_java_finalize);
187   DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
188   AcquireGlobal(thr);
189 }
190 
191 void __tsan_java_mutex_lock(jptr addr) {
192   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
193   DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
194   CHECK_NE(jctx, 0);
195   CHECK_GE(addr, jctx->heap_begin);
196   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
197 
198   MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
199       MutexFlagDoPreLockOnPostLock);
200 }
201 
202 void __tsan_java_mutex_unlock(jptr addr) {
203   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
204   DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
205   CHECK_NE(jctx, 0);
206   CHECK_GE(addr, jctx->heap_begin);
207   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
208 
209   MutexUnlock(thr, pc, addr);
210 }
211 
212 void __tsan_java_mutex_read_lock(jptr addr) {
213   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
214   DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
215   CHECK_NE(jctx, 0);
216   CHECK_GE(addr, jctx->heap_begin);
217   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
218 
219   MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit |
220       MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock);
221 }
222 
223 void __tsan_java_mutex_read_unlock(jptr addr) {
224   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
225   DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
226   CHECK_NE(jctx, 0);
227   CHECK_GE(addr, jctx->heap_begin);
228   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
229 
230   MutexReadUnlock(thr, pc, addr);
231 }
232 
233 void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
234   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
235   DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
236   CHECK_NE(jctx, 0);
237   CHECK_GE(addr, jctx->heap_begin);
238   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
239   CHECK_GT(rec, 0);
240 
241   MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
242       MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec);
243 }
244 
245 int __tsan_java_mutex_unlock_rec(jptr addr) {
246   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
247   DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
248   CHECK_NE(jctx, 0);
249   CHECK_GE(addr, jctx->heap_begin);
250   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
251 
252   return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock);
253 }
254 
255 void __tsan_java_acquire(jptr addr) {
256   SCOPED_JAVA_FUNC(__tsan_java_acquire);
257   DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr);
258   CHECK_NE(jctx, 0);
259   CHECK_GE(addr, jctx->heap_begin);
260   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
261 
262   Acquire(thr, caller_pc, addr);
263 }
264 
265 void __tsan_java_release(jptr addr) {
266   SCOPED_JAVA_FUNC(__tsan_java_release);
267   DPrintf("#%d: java_release(%p)\n", thr->tid, addr);
268   CHECK_NE(jctx, 0);
269   CHECK_GE(addr, jctx->heap_begin);
270   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
271 
272   Release(thr, caller_pc, addr);
273 }
274 
275 void __tsan_java_release_store(jptr addr) {
276   SCOPED_JAVA_FUNC(__tsan_java_release);
277   DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr);
278   CHECK_NE(jctx, 0);
279   CHECK_GE(addr, jctx->heap_begin);
280   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
281 
282   ReleaseStore(thr, caller_pc, addr);
283 }
284