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
21using namespace __tsan;  // NOLINT
22
23const jptr kHeapAlignment = 8;
24
25namespace __tsan {
26
27struct 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
37class 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
54static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
55static 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
67void __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
79int  __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
89void __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
102void __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
115void __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
151jptr __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
168void __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
174void __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
185void __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
195void __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
206void __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
216void __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
228int __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
238void __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
248void __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
258void __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