blob: 358fd15ddef3bbf2c6cd0bb298dfdc22040aa73b [file] [log] [blame]
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +00001//===-- 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"
Dmitry Vyukov2547ac62012-12-20 17:29:34 +000016#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"
Dmitry Vyukov5cf581a2013-06-17 19:57:03 +000020#include "sanitizer_common/sanitizer_stacktrace.h"
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +000021
22using namespace __tsan; // NOLINT
23
Dmitry Vyukov2547ac62012-12-20 17:29:34 +000024namespace __tsan {
25
26const uptr kHeapShadow = 0x300000000000ull;
27const uptr kHeapAlignment = 8;
28
29struct BlockDesc {
30 bool begin;
31 Mutex mtx;
32 SyncVar *head;
33
34 BlockDesc()
Dmitry Vyukov22be55e2012-12-21 11:30:14 +000035 : mtx(MutexTypeJavaMBlock, StatMtxJavaMBlock)
Dmitry Vyukov2547ac62012-12-20 17:29:34 +000036 , head() {
37 CHECK_EQ(begin, false);
38 begin = true;
39 }
40
Dmitry Vyukov2547ac62012-12-20 17:29:34 +000041 ~BlockDesc() {
42 CHECK_EQ(begin, true);
43 begin = false;
44 ThreadState *thr = cur_thread();
45 SyncVar *s = head;
46 while (s) {
47 SyncVar *s1 = s->next;
48 StatInc(thr, StatSyncDestroyed);
49 s->mtx.Lock();
50 s->mtx.Unlock();
51 thr->mset.Remove(s->GetId());
52 DestroyAndFree(s);
53 s = s1;
54 }
55 }
56};
57
58struct JavaContext {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +000059 const uptr heap_begin;
60 const uptr heap_size;
61 BlockDesc *heap_shadow;
62
63 JavaContext(jptr heap_begin, jptr heap_size)
Dmitry Vyukov22be55e2012-12-21 11:30:14 +000064 : heap_begin(heap_begin)
Dmitry Vyukov2547ac62012-12-20 17:29:34 +000065 , heap_size(heap_size) {
66 uptr size = heap_size / kHeapAlignment * sizeof(BlockDesc);
67 heap_shadow = (BlockDesc*)MmapFixedNoReserve(kHeapShadow, size);
68 if ((uptr)heap_shadow != kHeapShadow) {
69 Printf("ThreadSanitizer: failed to mmap Java heap shadow\n");
70 Die();
71 }
72 }
73};
74
75class ScopedJavaFunc {
76 public:
77 ScopedJavaFunc(ThreadState *thr, uptr pc)
78 : thr_(thr) {
79 Initialize(thr_);
80 FuncEntry(thr, pc);
81 CHECK_EQ(thr_->in_rtl, 0);
82 thr_->in_rtl++;
83 }
84
85 ~ScopedJavaFunc() {
86 thr_->in_rtl--;
87 CHECK_EQ(thr_->in_rtl, 0);
88 FuncExit(thr_);
89 // FIXME(dvyukov): process pending signals.
90 }
91
92 private:
93 ThreadState *thr_;
94};
95
96static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
97static JavaContext *jctx;
98
99static BlockDesc *getblock(uptr addr) {
100 uptr i = (addr - jctx->heap_begin) / kHeapAlignment;
101 return &jctx->heap_shadow[i];
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000102}
103
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000104static uptr USED getmem(BlockDesc *b) {
105 uptr i = b - jctx->heap_shadow;
106 uptr p = jctx->heap_begin + i * kHeapAlignment;
107 CHECK_GE(p, jctx->heap_begin);
108 CHECK_LT(p, jctx->heap_begin + jctx->heap_size);
109 return p;
110}
111
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000112static BlockDesc *getblockbegin(uptr addr) {
113 for (BlockDesc *b = getblock(addr);; b--) {
114 CHECK_GE(b, jctx->heap_shadow);
115 if (b->begin)
116 return b;
117 }
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000118 return 0;
119}
120
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000121SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr,
122 bool write_lock, bool create) {
123 if (jctx == 0 || addr < jctx->heap_begin
124 || addr >= jctx->heap_begin + jctx->heap_size)
125 return 0;
126 BlockDesc *b = getblockbegin(addr);
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000127 DPrintf("#%d: GetJavaSync %p->%p\n", thr->tid, addr, b);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000128 Lock l(&b->mtx);
129 SyncVar *s = b->head;
130 for (; s; s = s->next) {
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000131 if (s->addr == addr) {
132 DPrintf("#%d: found existing sync for %p\n", thr->tid, addr);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000133 break;
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000134 }
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000135 }
136 if (s == 0 && create) {
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000137 DPrintf("#%d: creating new sync for %p\n", thr->tid, addr);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000138 s = CTX()->synctab.Create(thr, pc, addr);
139 s->next = b->head;
140 b->head = s;
141 }
142 if (s) {
143 if (write_lock)
144 s->mtx.Lock();
145 else
146 s->mtx.ReadLock();
147 }
148 return s;
149}
150
151SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
152 // We do not destroy Java mutexes other than in __tsan_java_free().
153 return 0;
154}
155
Alexey Samsonov49a32c12013-01-30 07:45:58 +0000156} // namespace __tsan
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000157
158#define SCOPED_JAVA_FUNC(func) \
159 ThreadState *thr = cur_thread(); \
160 const uptr caller_pc = GET_CALLER_PC(); \
Dmitry Vyukov5cf581a2013-06-17 19:57:03 +0000161 const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000162 (void)pc; \
163 ScopedJavaFunc scoped(thr, caller_pc); \
164/**/
165
166void __tsan_java_init(jptr heap_begin, jptr heap_size) {
167 SCOPED_JAVA_FUNC(__tsan_java_init);
168 DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
169 CHECK_EQ(jctx, 0);
170 CHECK_GT(heap_begin, 0);
171 CHECK_GT(heap_size, 0);
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000172 CHECK_EQ(heap_begin % kHeapAlignment, 0);
173 CHECK_EQ(heap_size % kHeapAlignment, 0);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000174 CHECK_LT(heap_begin, heap_begin + heap_size);
175 jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
176}
177
178int __tsan_java_fini() {
179 SCOPED_JAVA_FUNC(__tsan_java_fini);
180 DPrintf("#%d: java_fini()\n", thr->tid);
181 CHECK_NE(jctx, 0);
182 // FIXME(dvyukov): this does not call atexit() callbacks.
183 int status = Finalize(thr);
184 DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
185 return status;
186}
187
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000188void __tsan_java_alloc(jptr ptr, jptr size) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000189 SCOPED_JAVA_FUNC(__tsan_java_alloc);
190 DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
191 CHECK_NE(jctx, 0);
192 CHECK_NE(size, 0);
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000193 CHECK_EQ(ptr % kHeapAlignment, 0);
194 CHECK_EQ(size % kHeapAlignment, 0);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000195 CHECK_GE(ptr, jctx->heap_begin);
196 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
197
198 BlockDesc *b = getblock(ptr);
199 new(b) BlockDesc();
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000200}
201
202void __tsan_java_free(jptr ptr, jptr size) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000203 SCOPED_JAVA_FUNC(__tsan_java_free);
204 DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
205 CHECK_NE(jctx, 0);
206 CHECK_NE(size, 0);
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000207 CHECK_EQ(ptr % kHeapAlignment, 0);
208 CHECK_EQ(size % kHeapAlignment, 0);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000209 CHECK_GE(ptr, jctx->heap_begin);
210 CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
211
212 BlockDesc *beg = getblock(ptr);
213 BlockDesc *end = getblock(ptr + size);
214 for (BlockDesc *b = beg; b != end; b++) {
215 if (b->begin)
216 b->~BlockDesc();
217 }
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000218}
219
220void __tsan_java_move(jptr src, jptr dst, jptr size) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000221 SCOPED_JAVA_FUNC(__tsan_java_move);
222 DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
223 CHECK_NE(jctx, 0);
224 CHECK_NE(size, 0);
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000225 CHECK_EQ(src % kHeapAlignment, 0);
226 CHECK_EQ(dst % kHeapAlignment, 0);
227 CHECK_EQ(size % kHeapAlignment, 0);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000228 CHECK_GE(src, jctx->heap_begin);
229 CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
230 CHECK_GE(dst, jctx->heap_begin);
231 CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
232 CHECK(dst >= src + size || src >= dst + size);
233
234 // Assuming it's not running concurrently with threads that do
235 // memory accesses and mutex operations (stop-the-world phase).
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000236 { // NOLINT
237 BlockDesc *s = getblock(src);
238 BlockDesc *d = getblock(dst);
239 BlockDesc *send = getblock(src + size);
240 for (; s != send; s++, d++) {
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000241 CHECK_EQ(d->begin, false);
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000242 if (s->begin) {
Dmitry Vyukova33bf272012-12-21 13:23:48 +0000243 DPrintf("#%d: moving block %p->%p\n", thr->tid, getmem(s), getmem(d));
244 new(d) BlockDesc;
245 d->head = s->head;
246 for (SyncVar *sync = d->head; sync; sync = sync->next) {
247 uptr newaddr = sync->addr - src + dst;
248 DPrintf("#%d: moving sync %p->%p\n", thr->tid, sync->addr, newaddr);
249 sync->addr = newaddr;
250 }
251 s->head = 0;
Dmitry Vyukova5b57102012-12-21 11:16:40 +0000252 s->~BlockDesc();
253 }
254 }
255 }
256
257 { // NOLINT
258 u64 *s = (u64*)MemToShadow(src);
259 u64 *d = (u64*)MemToShadow(dst);
260 u64 *send = (u64*)MemToShadow(src + size);
261 for (; s != send; s++, d++) {
262 *d = *s;
263 *s = 0;
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000264 }
265 }
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000266}
267
268void __tsan_java_mutex_lock(jptr addr) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000269 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
270 DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
271 CHECK_NE(jctx, 0);
272 CHECK_GE(addr, jctx->heap_begin);
273 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
274
Dmitry Vyukovc9af8182013-05-17 12:03:46 +0000275 MutexCreate(thr, pc, addr, true, true, true);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000276 MutexLock(thr, pc, addr);
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000277}
278
279void __tsan_java_mutex_unlock(jptr addr) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000280 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
281 DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
282 CHECK_NE(jctx, 0);
283 CHECK_GE(addr, jctx->heap_begin);
284 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
285
286 MutexUnlock(thr, pc, addr);
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000287}
288
289void __tsan_java_mutex_read_lock(jptr addr) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000290 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
291 DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
292 CHECK_NE(jctx, 0);
293 CHECK_GE(addr, jctx->heap_begin);
294 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
295
Dmitry Vyukovc9af8182013-05-17 12:03:46 +0000296 MutexCreate(thr, pc, addr, true, true, true);
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000297 MutexReadLock(thr, pc, addr);
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000298}
299
300void __tsan_java_mutex_read_unlock(jptr addr) {
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000301 SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
302 DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
303 CHECK_NE(jctx, 0);
304 CHECK_GE(addr, jctx->heap_begin);
305 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
Dmitry Vyukovd088b3b2012-12-20 10:21:30 +0000306
Dmitry Vyukov2547ac62012-12-20 17:29:34 +0000307 MutexReadUnlock(thr, pc, addr);
308}
Dmitry Vyukovc9af8182013-05-17 12:03:46 +0000309
310void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
311 SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
312 DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
313 CHECK_NE(jctx, 0);
314 CHECK_GE(addr, jctx->heap_begin);
315 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
316 CHECK_GT(rec, 0);
317
318 MutexCreate(thr, pc, addr, true, true, true);
319 MutexLock(thr, pc, addr, rec);
320}
321
322int __tsan_java_mutex_unlock_rec(jptr addr) {
323 SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
324 DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
325 CHECK_NE(jctx, 0);
326 CHECK_GE(addr, jctx->heap_begin);
327 CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
328
329 return MutexUnlock(thr, pc, addr, true);
330}