tsan_interface_java.cpp revision 1.1
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
22using namespace __tsan;
23
24const jptr kHeapAlignment = 8;
25
26namespace __tsan {
27
28struct JavaContext {
29  const uptr heap_begin;
30  const uptr heap_size;
31
32  JavaContext(jptr heap_begin, jptr heap_size)
33      : heap_begin(heap_begin)
34      , heap_size(heap_size) {
35  }
36};
37
38class ScopedJavaFunc {
39 public:
40  ScopedJavaFunc(ThreadState *thr, uptr pc)
41      : thr_(thr) {
42    Initialize(thr_);
43    FuncEntry(thr, pc);
44  }
45
46  ~ScopedJavaFunc() {
47    FuncExit(thr_);
48    // FIXME(dvyukov): process pending signals.
49  }
50
51 private:
52  ThreadState *thr_;
53};
54
55static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
56static 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
68void __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
80int  __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
90void __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
103void __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
116void __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
152jptr __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
169void __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
175void __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
186void __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
196void __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
207void __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
217void __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
229int __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
239void __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
249void __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
259void __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