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