xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/tsan/tsan_interface_java.cc (revision a2dc1f3faca890bc62c61c70cbcb4657d1fe6044)
1 //===-- tsan_interface_java.cc --------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
9 //
10 //===----------------------------------------------------------------------===//
11 
12 #include "tsan_interface_java.h"
13 #include "tsan_rtl.h"
14 #include "tsan_mutex.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;  // NOLINT
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 
JavaContext__tsan::JavaContext31   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:
ScopedJavaFunc(ThreadState * thr,uptr pc)39   ScopedJavaFunc(ThreadState *thr, uptr pc)
40       : thr_(thr) {
41     Initialize(thr_);
42     FuncEntry(thr, pc);
43   }
44 
~ScopedJavaFunc()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 
__tsan_java_init(jptr heap_begin,jptr heap_size)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 
__tsan_java_fini()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 
__tsan_java_alloc(jptr ptr,jptr size)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 
__tsan_java_free(jptr ptr,jptr size)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 
__tsan_java_move(jptr src,jptr dst,jptr size)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 
__tsan_java_find(jptr * from_ptr,jptr to)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 
__tsan_java_finalize()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 
__tsan_java_mutex_lock(jptr addr)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 
__tsan_java_mutex_unlock(jptr addr)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 
__tsan_java_mutex_read_lock(jptr addr)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 
__tsan_java_mutex_read_unlock(jptr addr)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 
__tsan_java_mutex_lock_rec(jptr addr,int rec)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 
__tsan_java_mutex_unlock_rec(jptr addr)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 
__tsan_java_acquire(jptr addr)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 
__tsan_java_release(jptr addr)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 
__tsan_java_release_store(jptr addr)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