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 
JavaContext__tsan::JavaContext31   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 
JavaHeapBlock(uptr addr,uptr * start)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 
__tsan_java_init(jptr heap_begin,jptr heap_size)63 void __tsan_java_init(jptr heap_begin, jptr heap_size) {
64   JAVA_FUNC_ENTER(__tsan_java_init);
65   Initialize(thr);
66   DPrintf("#%d: java_init(0x%zx, 0x%zx)\n", thr->tid, heap_begin, heap_size);
67   DCHECK_EQ(jctx, 0);
68   DCHECK_GT(heap_begin, 0);
69   DCHECK_GT(heap_size, 0);
70   DCHECK_EQ(heap_begin % kHeapAlignment, 0);
71   DCHECK_EQ(heap_size % kHeapAlignment, 0);
72   DCHECK_LT(heap_begin, heap_begin + heap_size);
73   jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
74 }
75 
__tsan_java_fini()76 int  __tsan_java_fini() {
77   JAVA_FUNC_ENTER(__tsan_java_fini);
78   DPrintf("#%d: java_fini()\n", thr->tid);
79   DCHECK_NE(jctx, 0);
80   // FIXME(dvyukov): this does not call atexit() callbacks.
81   int status = Finalize(thr);
82   DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
83   return status;
84 }
85 
__tsan_java_alloc(jptr ptr,jptr size)86 void __tsan_java_alloc(jptr ptr, jptr size) {
87   JAVA_FUNC_ENTER(__tsan_java_alloc);
88   DPrintf("#%d: java_alloc(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
89   DCHECK_NE(jctx, 0);
90   DCHECK_NE(size, 0);
91   DCHECK_EQ(ptr % kHeapAlignment, 0);
92   DCHECK_EQ(size % kHeapAlignment, 0);
93   DCHECK_GE(ptr, jctx->heap_begin);
94   DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
95 
96   OnUserAlloc(thr, 0, ptr, size, false);
97 }
98 
__tsan_java_free(jptr ptr,jptr size)99 void __tsan_java_free(jptr ptr, jptr size) {
100   JAVA_FUNC_ENTER(__tsan_java_free);
101   DPrintf("#%d: java_free(0x%zx, 0x%zx)\n", thr->tid, ptr, size);
102   DCHECK_NE(jctx, 0);
103   DCHECK_NE(size, 0);
104   DCHECK_EQ(ptr % kHeapAlignment, 0);
105   DCHECK_EQ(size % kHeapAlignment, 0);
106   DCHECK_GE(ptr, jctx->heap_begin);
107   DCHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
108 
109   ctx->metamap.FreeRange(thr->proc(), ptr, size, false);
110 }
111 
__tsan_java_move(jptr src,jptr dst,jptr size)112 void __tsan_java_move(jptr src, jptr dst, jptr size) {
113   JAVA_FUNC_ENTER(__tsan_java_move);
114   DPrintf("#%d: java_move(0x%zx, 0x%zx, 0x%zx)\n", thr->tid, src, dst, size);
115   DCHECK_NE(jctx, 0);
116   DCHECK_NE(size, 0);
117   DCHECK_EQ(src % kHeapAlignment, 0);
118   DCHECK_EQ(dst % kHeapAlignment, 0);
119   DCHECK_EQ(size % kHeapAlignment, 0);
120   DCHECK_GE(src, jctx->heap_begin);
121   DCHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
122   DCHECK_GE(dst, jctx->heap_begin);
123   DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
124   DCHECK_NE(dst, src);
125   DCHECK_NE(size, 0);
126 
127   // Assuming it's not running concurrently with threads that do
128   // memory accesses and mutex operations (stop-the-world phase).
129   ctx->metamap.MoveMemory(src, dst, size);
130 
131   // Clear the destination shadow range.
132   // We used to move shadow from src to dst, but the trace format does not
133   // support that anymore as it contains addresses of accesses.
134   RawShadow *d = MemToShadow(dst);
135   RawShadow *dend = MemToShadow(dst + size);
136   ShadowSet(d, dend, Shadow::kEmpty);
137 }
138 
__tsan_java_find(jptr * from_ptr,jptr to)139 jptr __tsan_java_find(jptr *from_ptr, jptr to) {
140   JAVA_FUNC_ENTER(__tsan_java_find);
141   DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
142   DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
143   DCHECK_EQ(to % kHeapAlignment, 0);
144   DCHECK_GE(*from_ptr, jctx->heap_begin);
145   DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
146   for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
147     MBlock *b = ctx->metamap.GetBlock(from);
148     if (b) {
149       *from_ptr = from;
150       return b->siz;
151     }
152   }
153   return 0;
154 }
155 
__tsan_java_finalize()156 void __tsan_java_finalize() {
157   JAVA_FUNC_ENTER(__tsan_java_finalize);
158   DPrintf("#%d: java_finalize()\n", thr->tid);
159   AcquireGlobal(thr);
160 }
161 
__tsan_java_mutex_lock(jptr addr)162 void __tsan_java_mutex_lock(jptr addr) {
163   JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
164   DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
165   DCHECK_NE(jctx, 0);
166   DCHECK_GE(addr, jctx->heap_begin);
167   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
168 
169   MutexPostLock(thr, 0, addr,
170                 MutexFlagLinkerInit | MutexFlagWriteReentrant |
171                     MutexFlagDoPreLockOnPostLock);
172 }
173 
__tsan_java_mutex_unlock(jptr addr)174 void __tsan_java_mutex_unlock(jptr addr) {
175   JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
176   DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
177   DCHECK_NE(jctx, 0);
178   DCHECK_GE(addr, jctx->heap_begin);
179   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
180 
181   MutexUnlock(thr, 0, addr);
182 }
183 
__tsan_java_mutex_read_lock(jptr addr)184 void __tsan_java_mutex_read_lock(jptr addr) {
185   JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
186   DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
187   DCHECK_NE(jctx, 0);
188   DCHECK_GE(addr, jctx->heap_begin);
189   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
190 
191   MutexPostReadLock(thr, 0, addr,
192                     MutexFlagLinkerInit | MutexFlagWriteReentrant |
193                         MutexFlagDoPreLockOnPostLock);
194 }
195 
__tsan_java_mutex_read_unlock(jptr addr)196 void __tsan_java_mutex_read_unlock(jptr addr) {
197   JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
198   DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
199   DCHECK_NE(jctx, 0);
200   DCHECK_GE(addr, jctx->heap_begin);
201   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
202 
203   MutexReadUnlock(thr, 0, addr);
204 }
205 
__tsan_java_mutex_lock_rec(jptr addr,int rec)206 void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
207   JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
208   DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
209   DCHECK_NE(jctx, 0);
210   DCHECK_GE(addr, jctx->heap_begin);
211   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
212   DCHECK_GT(rec, 0);
213 
214   MutexPostLock(thr, 0, addr,
215                 MutexFlagLinkerInit | MutexFlagWriteReentrant |
216                     MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
217                 rec);
218 }
219 
__tsan_java_mutex_unlock_rec(jptr addr)220 int __tsan_java_mutex_unlock_rec(jptr addr) {
221   JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
222   DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
223   DCHECK_NE(jctx, 0);
224   DCHECK_GE(addr, jctx->heap_begin);
225   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
226 
227   return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
228 }
229 
__tsan_java_acquire(jptr addr)230 void __tsan_java_acquire(jptr addr) {
231   JAVA_FUNC_ENTER(__tsan_java_acquire);
232   DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
233   DCHECK_NE(jctx, 0);
234   DCHECK_GE(addr, jctx->heap_begin);
235   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
236 
237   Acquire(thr, 0, addr);
238 }
239 
__tsan_java_release(jptr addr)240 void __tsan_java_release(jptr addr) {
241   JAVA_FUNC_ENTER(__tsan_java_release);
242   DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
243   DCHECK_NE(jctx, 0);
244   DCHECK_GE(addr, jctx->heap_begin);
245   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
246 
247   Release(thr, 0, addr);
248 }
249 
__tsan_java_release_store(jptr addr)250 void __tsan_java_release_store(jptr addr) {
251   JAVA_FUNC_ENTER(__tsan_java_release);
252   DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
253   DCHECK_NE(jctx, 0);
254   DCHECK_GE(addr, jctx->heap_begin);
255   DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
256 
257   ReleaseStore(thr, 0, addr);
258 }
259