master
  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
 21using namespace __tsan;
 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
 37static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
 38static JavaContext *jctx;
 39
 40MBlock *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
 63void __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
 76int  __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
 86void __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
 99void __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
112void __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
126  // Assuming it's not running concurrently with threads that do
127  // memory accesses and mutex operations (stop-the-world phase).
128  ctx->metamap.MoveMemory(src, dst, size);
129
130  // Clear the destination shadow range.
131  // We used to move shadow from src to dst, but the trace format does not
132  // support that anymore as it contains addresses of accesses.
133  RawShadow *d = MemToShadow(dst);
134  RawShadow *dend = MemToShadow(dst + size);
135  ShadowSet(d, dend, Shadow::kEmpty);
136}
137
138jptr __tsan_java_find(jptr *from_ptr, jptr to) {
139  JAVA_FUNC_ENTER(__tsan_java_find);
140  DPrintf("#%d: java_find(&0x%zx, 0x%zx)\n", thr->tid, *from_ptr, to);
141  DCHECK_EQ((*from_ptr) % kHeapAlignment, 0);
142  DCHECK_EQ(to % kHeapAlignment, 0);
143  DCHECK_GE(*from_ptr, jctx->heap_begin);
144  DCHECK_LE(to, jctx->heap_begin + jctx->heap_size);
145  for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
146    MBlock *b = ctx->metamap.GetBlock(from);
147    if (b) {
148      *from_ptr = from;
149      return b->siz;
150    }
151  }
152  return 0;
153}
154
155void __tsan_java_finalize() {
156  JAVA_FUNC_ENTER(__tsan_java_finalize);
157  DPrintf("#%d: java_finalize()\n", thr->tid);
158  AcquireGlobal(thr);
159}
160
161void __tsan_java_mutex_lock(jptr addr) {
162  JAVA_FUNC_ENTER(__tsan_java_mutex_lock);
163  DPrintf("#%d: java_mutex_lock(0x%zx)\n", thr->tid, addr);
164  DCHECK_NE(jctx, 0);
165  DCHECK_GE(addr, jctx->heap_begin);
166  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
167
168  MutexPostLock(thr, 0, addr,
169                MutexFlagLinkerInit | MutexFlagWriteReentrant |
170                    MutexFlagDoPreLockOnPostLock);
171}
172
173void __tsan_java_mutex_unlock(jptr addr) {
174  JAVA_FUNC_ENTER(__tsan_java_mutex_unlock);
175  DPrintf("#%d: java_mutex_unlock(0x%zx)\n", thr->tid, addr);
176  DCHECK_NE(jctx, 0);
177  DCHECK_GE(addr, jctx->heap_begin);
178  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
179
180  MutexUnlock(thr, 0, addr);
181}
182
183void __tsan_java_mutex_read_lock(jptr addr) {
184  JAVA_FUNC_ENTER(__tsan_java_mutex_read_lock);
185  DPrintf("#%d: java_mutex_read_lock(0x%zx)\n", thr->tid, addr);
186  DCHECK_NE(jctx, 0);
187  DCHECK_GE(addr, jctx->heap_begin);
188  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
189
190  MutexPostReadLock(thr, 0, addr,
191                    MutexFlagLinkerInit | MutexFlagWriteReentrant |
192                        MutexFlagDoPreLockOnPostLock);
193}
194
195void __tsan_java_mutex_read_unlock(jptr addr) {
196  JAVA_FUNC_ENTER(__tsan_java_mutex_read_unlock);
197  DPrintf("#%d: java_mutex_read_unlock(0x%zx)\n", thr->tid, addr);
198  DCHECK_NE(jctx, 0);
199  DCHECK_GE(addr, jctx->heap_begin);
200  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
201
202  MutexReadUnlock(thr, 0, addr);
203}
204
205void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
206  JAVA_FUNC_ENTER(__tsan_java_mutex_lock_rec);
207  DPrintf("#%d: java_mutex_lock_rec(0x%zx, %d)\n", thr->tid, addr, rec);
208  DCHECK_NE(jctx, 0);
209  DCHECK_GE(addr, jctx->heap_begin);
210  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
211  DCHECK_GT(rec, 0);
212
213  MutexPostLock(thr, 0, addr,
214                MutexFlagLinkerInit | MutexFlagWriteReentrant |
215                    MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock,
216                rec);
217}
218
219int __tsan_java_mutex_unlock_rec(jptr addr) {
220  JAVA_FUNC_ENTER(__tsan_java_mutex_unlock_rec);
221  DPrintf("#%d: java_mutex_unlock_rec(0x%zx)\n", thr->tid, addr);
222  DCHECK_NE(jctx, 0);
223  DCHECK_GE(addr, jctx->heap_begin);
224  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
225
226  return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock);
227}
228
229void __tsan_java_acquire(jptr addr) {
230  JAVA_FUNC_ENTER(__tsan_java_acquire);
231  DPrintf("#%d: java_acquire(0x%zx)\n", thr->tid, addr);
232  DCHECK_NE(jctx, 0);
233  DCHECK_GE(addr, jctx->heap_begin);
234  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
235
236  Acquire(thr, 0, addr);
237}
238
239void __tsan_java_release(jptr addr) {
240  JAVA_FUNC_ENTER(__tsan_java_release);
241  DPrintf("#%d: java_release(0x%zx)\n", thr->tid, addr);
242  DCHECK_NE(jctx, 0);
243  DCHECK_GE(addr, jctx->heap_begin);
244  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
245
246  Release(thr, 0, addr);
247}
248
249void __tsan_java_release_store(jptr addr) {
250  JAVA_FUNC_ENTER(__tsan_java_release);
251  DPrintf("#%d: java_release_store(0x%zx)\n", thr->tid, addr);
252  DCHECK_NE(jctx, 0);
253  DCHECK_GE(addr, jctx->heap_begin);
254  DCHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
255
256  ReleaseStore(thr, 0, addr);
257}