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