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