15a3bb1a4SNico Weber //===-- tsan_interface_java.cpp -------------------------------------------===// 25a3bb1a4SNico Weber // 35a3bb1a4SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45a3bb1a4SNico Weber // See https://llvm.org/LICENSE.txt for license information. 55a3bb1a4SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65a3bb1a4SNico Weber // 75a3bb1a4SNico Weber //===----------------------------------------------------------------------===// 85a3bb1a4SNico Weber // 95a3bb1a4SNico Weber // This file is a part of ThreadSanitizer (TSan), a race detector. 105a3bb1a4SNico Weber // 115a3bb1a4SNico Weber //===----------------------------------------------------------------------===// 125a3bb1a4SNico Weber 135a3bb1a4SNico Weber #include "tsan_interface_java.h" 145a3bb1a4SNico Weber #include "tsan_rtl.h" 155a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_internal_defs.h" 165a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_common.h" 175a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_placement_new.h" 185a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_stacktrace.h" 195a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_procmaps.h" 205a3bb1a4SNico Weber 21c0fa6322SVitaly Buka using namespace __tsan; 225a3bb1a4SNico Weber 235a3bb1a4SNico Weber const jptr kHeapAlignment = 8; 245a3bb1a4SNico Weber 255a3bb1a4SNico Weber namespace __tsan { 265a3bb1a4SNico Weber 275a3bb1a4SNico Weber struct JavaContext { 285a3bb1a4SNico Weber const uptr heap_begin; 295a3bb1a4SNico Weber const uptr heap_size; 305a3bb1a4SNico Weber 315a3bb1a4SNico Weber JavaContext(jptr heap_begin, jptr heap_size) 325a3bb1a4SNico Weber : heap_begin(heap_begin) 335a3bb1a4SNico Weber , heap_size(heap_size) { 345a3bb1a4SNico Weber } 355a3bb1a4SNico Weber }; 365a3bb1a4SNico Weber 375a3bb1a4SNico Weber static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; 385a3bb1a4SNico Weber static JavaContext *jctx; 395a3bb1a4SNico Weber 405237b140SDmitry Vyukov MBlock *JavaHeapBlock(uptr addr, uptr *start) { 415237b140SDmitry Vyukov if (!jctx || addr < jctx->heap_begin || 425237b140SDmitry Vyukov addr >= jctx->heap_begin + jctx->heap_size) 435237b140SDmitry Vyukov return nullptr; 445237b140SDmitry Vyukov for (uptr p = RoundDown(addr, kMetaShadowCell); p >= jctx->heap_begin; 455237b140SDmitry Vyukov p -= kMetaShadowCell) { 465237b140SDmitry Vyukov MBlock *b = ctx->metamap.GetBlock(p); 475237b140SDmitry Vyukov if (!b) 485237b140SDmitry Vyukov continue; 495237b140SDmitry Vyukov if (p + b->siz <= addr) 505237b140SDmitry Vyukov return nullptr; 515237b140SDmitry Vyukov *start = p; 525237b140SDmitry Vyukov return b; 535237b140SDmitry Vyukov } 545237b140SDmitry Vyukov return nullptr; 555237b140SDmitry Vyukov } 565237b140SDmitry Vyukov 575a3bb1a4SNico Weber } // namespace __tsan 585a3bb1a4SNico Weber 595a3bb1a4SNico Weber #define SCOPED_JAVA_FUNC(func) \ 605a3bb1a4SNico Weber ThreadState *thr = cur_thread(); \ 61*6563bb53SDmitry Vyukov (void)thr; \ 625a3bb1a4SNico Weber /**/ 635a3bb1a4SNico Weber 645a3bb1a4SNico Weber void __tsan_java_init(jptr heap_begin, jptr heap_size) { 655a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_init); 665a3bb1a4SNico Weber DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); 675a3bb1a4SNico Weber CHECK_EQ(jctx, 0); 685a3bb1a4SNico Weber CHECK_GT(heap_begin, 0); 695a3bb1a4SNico Weber CHECK_GT(heap_size, 0); 705a3bb1a4SNico Weber CHECK_EQ(heap_begin % kHeapAlignment, 0); 715a3bb1a4SNico Weber CHECK_EQ(heap_size % kHeapAlignment, 0); 725a3bb1a4SNico Weber CHECK_LT(heap_begin, heap_begin + heap_size); 735a3bb1a4SNico Weber jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); 745a3bb1a4SNico Weber } 755a3bb1a4SNico Weber 765a3bb1a4SNico Weber int __tsan_java_fini() { 775a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_fini); 785a3bb1a4SNico Weber DPrintf("#%d: java_fini()\n", thr->tid); 795a3bb1a4SNico Weber CHECK_NE(jctx, 0); 805a3bb1a4SNico Weber // FIXME(dvyukov): this does not call atexit() callbacks. 815a3bb1a4SNico Weber int status = Finalize(thr); 825a3bb1a4SNico Weber DPrintf("#%d: java_fini() = %d\n", thr->tid, status); 835a3bb1a4SNico Weber return status; 845a3bb1a4SNico Weber } 855a3bb1a4SNico Weber 865a3bb1a4SNico Weber void __tsan_java_alloc(jptr ptr, jptr size) { 875a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_alloc); 885a3bb1a4SNico Weber DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); 895a3bb1a4SNico Weber CHECK_NE(jctx, 0); 905a3bb1a4SNico Weber CHECK_NE(size, 0); 915a3bb1a4SNico Weber CHECK_EQ(ptr % kHeapAlignment, 0); 925a3bb1a4SNico Weber CHECK_EQ(size % kHeapAlignment, 0); 935a3bb1a4SNico Weber CHECK_GE(ptr, jctx->heap_begin); 945a3bb1a4SNico Weber CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 955a3bb1a4SNico Weber 96*6563bb53SDmitry Vyukov OnUserAlloc(thr, 0, ptr, size, false); 975a3bb1a4SNico Weber } 985a3bb1a4SNico Weber 995a3bb1a4SNico Weber void __tsan_java_free(jptr ptr, jptr size) { 1005a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_free); 1015a3bb1a4SNico Weber DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); 1025a3bb1a4SNico Weber CHECK_NE(jctx, 0); 1035a3bb1a4SNico Weber CHECK_NE(size, 0); 1045a3bb1a4SNico Weber CHECK_EQ(ptr % kHeapAlignment, 0); 1055a3bb1a4SNico Weber CHECK_EQ(size % kHeapAlignment, 0); 1065a3bb1a4SNico Weber CHECK_GE(ptr, jctx->heap_begin); 1075a3bb1a4SNico Weber CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); 1085a3bb1a4SNico Weber 1095a3bb1a4SNico Weber ctx->metamap.FreeRange(thr->proc(), ptr, size); 1105a3bb1a4SNico Weber } 1115a3bb1a4SNico Weber 1125a3bb1a4SNico Weber void __tsan_java_move(jptr src, jptr dst, jptr size) { 1135a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_move); 1145a3bb1a4SNico Weber DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); 1155a3bb1a4SNico Weber CHECK_NE(jctx, 0); 1165a3bb1a4SNico Weber CHECK_NE(size, 0); 1175a3bb1a4SNico Weber CHECK_EQ(src % kHeapAlignment, 0); 1185a3bb1a4SNico Weber CHECK_EQ(dst % kHeapAlignment, 0); 1195a3bb1a4SNico Weber CHECK_EQ(size % kHeapAlignment, 0); 1205a3bb1a4SNico Weber CHECK_GE(src, jctx->heap_begin); 1215a3bb1a4SNico Weber CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); 1225a3bb1a4SNico Weber CHECK_GE(dst, jctx->heap_begin); 1235a3bb1a4SNico Weber CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); 1245a3bb1a4SNico Weber CHECK_NE(dst, src); 1255a3bb1a4SNico Weber CHECK_NE(size, 0); 1265a3bb1a4SNico Weber 1275a3bb1a4SNico Weber // Assuming it's not running concurrently with threads that do 1285a3bb1a4SNico Weber // memory accesses and mutex operations (stop-the-world phase). 1295a3bb1a4SNico Weber ctx->metamap.MoveMemory(src, dst, size); 1305a3bb1a4SNico Weber 1315a3bb1a4SNico Weber // Move shadow. 1325a3bb1a4SNico Weber u64 *s = (u64*)MemToShadow(src); 1335a3bb1a4SNico Weber u64 *d = (u64*)MemToShadow(dst); 1345a3bb1a4SNico Weber u64 *send = (u64*)MemToShadow(src + size); 1355a3bb1a4SNico Weber uptr inc = 1; 1365a3bb1a4SNico Weber if (dst > src) { 1375a3bb1a4SNico Weber s = (u64*)MemToShadow(src + size) - 1; 1385a3bb1a4SNico Weber d = (u64*)MemToShadow(dst + size) - 1; 1395a3bb1a4SNico Weber send = (u64*)MemToShadow(src) - 1; 1405a3bb1a4SNico Weber inc = -1; 1415a3bb1a4SNico Weber } 1425a3bb1a4SNico Weber for (; s != send; s += inc, d += inc) { 1435a3bb1a4SNico Weber *d = *s; 1445a3bb1a4SNico Weber *s = 0; 1455a3bb1a4SNico Weber } 1465a3bb1a4SNico Weber } 1475a3bb1a4SNico Weber 1485a3bb1a4SNico Weber jptr __tsan_java_find(jptr *from_ptr, jptr to) { 1495a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_find); 1505a3bb1a4SNico Weber DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); 1515a3bb1a4SNico Weber CHECK_EQ((*from_ptr) % kHeapAlignment, 0); 1525a3bb1a4SNico Weber CHECK_EQ(to % kHeapAlignment, 0); 1535a3bb1a4SNico Weber CHECK_GE(*from_ptr, jctx->heap_begin); 1545a3bb1a4SNico Weber CHECK_LE(to, jctx->heap_begin + jctx->heap_size); 1555a3bb1a4SNico Weber for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { 1565a3bb1a4SNico Weber MBlock *b = ctx->metamap.GetBlock(from); 1575a3bb1a4SNico Weber if (b) { 1585a3bb1a4SNico Weber *from_ptr = from; 1595a3bb1a4SNico Weber return b->siz; 1605a3bb1a4SNico Weber } 1615a3bb1a4SNico Weber } 1625a3bb1a4SNico Weber return 0; 1635a3bb1a4SNico Weber } 1645a3bb1a4SNico Weber 1655a3bb1a4SNico Weber void __tsan_java_finalize() { 1665a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_finalize); 1675a3bb1a4SNico Weber DPrintf("#%d: java_mutex_finalize()\n", thr->tid); 1685acdfb7eSDmitry Vyukov AcquireGlobal(thr); 1695a3bb1a4SNico Weber } 1705a3bb1a4SNico Weber 1715a3bb1a4SNico Weber void __tsan_java_mutex_lock(jptr addr) { 1725a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_mutex_lock); 1735a3bb1a4SNico Weber DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); 1745a3bb1a4SNico Weber CHECK_NE(jctx, 0); 1755a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 1765a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 1775a3bb1a4SNico Weber 178*6563bb53SDmitry Vyukov MutexPostLock(thr, 0, addr, 179*6563bb53SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant | 1805a3bb1a4SNico Weber MutexFlagDoPreLockOnPostLock); 1815a3bb1a4SNico Weber } 1825a3bb1a4SNico Weber 1835a3bb1a4SNico Weber void __tsan_java_mutex_unlock(jptr addr) { 1845a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock); 1855a3bb1a4SNico Weber DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); 1865a3bb1a4SNico Weber CHECK_NE(jctx, 0); 1875a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 1885a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 1895a3bb1a4SNico Weber 190*6563bb53SDmitry Vyukov MutexUnlock(thr, 0, addr); 1915a3bb1a4SNico Weber } 1925a3bb1a4SNico Weber 1935a3bb1a4SNico Weber void __tsan_java_mutex_read_lock(jptr addr) { 1945a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock); 1955a3bb1a4SNico Weber DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); 1965a3bb1a4SNico Weber CHECK_NE(jctx, 0); 1975a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 1985a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 1995a3bb1a4SNico Weber 200*6563bb53SDmitry Vyukov MutexPostReadLock(thr, 0, addr, 201*6563bb53SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant | 202*6563bb53SDmitry Vyukov MutexFlagDoPreLockOnPostLock); 2035a3bb1a4SNico Weber } 2045a3bb1a4SNico Weber 2055a3bb1a4SNico Weber void __tsan_java_mutex_read_unlock(jptr addr) { 2065a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock); 2075a3bb1a4SNico Weber DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); 2085a3bb1a4SNico Weber CHECK_NE(jctx, 0); 2095a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 2105a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 2115a3bb1a4SNico Weber 212*6563bb53SDmitry Vyukov MutexReadUnlock(thr, 0, addr); 2135a3bb1a4SNico Weber } 2145a3bb1a4SNico Weber 2155a3bb1a4SNico Weber void __tsan_java_mutex_lock_rec(jptr addr, int rec) { 2165a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); 2175a3bb1a4SNico Weber DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); 2185a3bb1a4SNico Weber CHECK_NE(jctx, 0); 2195a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 2205a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 2215a3bb1a4SNico Weber CHECK_GT(rec, 0); 2225a3bb1a4SNico Weber 223*6563bb53SDmitry Vyukov MutexPostLock(thr, 0, addr, 224*6563bb53SDmitry Vyukov MutexFlagLinkerInit | MutexFlagWriteReentrant | 225*6563bb53SDmitry Vyukov MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, 226*6563bb53SDmitry Vyukov rec); 2275a3bb1a4SNico Weber } 2285a3bb1a4SNico Weber 2295a3bb1a4SNico Weber int __tsan_java_mutex_unlock_rec(jptr addr) { 2305a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec); 2315a3bb1a4SNico Weber DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr); 2325a3bb1a4SNico Weber CHECK_NE(jctx, 0); 2335a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 2345a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 2355a3bb1a4SNico Weber 236*6563bb53SDmitry Vyukov return MutexUnlock(thr, 0, addr, MutexFlagRecursiveUnlock); 2375a3bb1a4SNico Weber } 2385a3bb1a4SNico Weber 2395a3bb1a4SNico Weber void __tsan_java_acquire(jptr addr) { 2405a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_acquire); 2415a3bb1a4SNico Weber DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr); 2425a3bb1a4SNico Weber CHECK_NE(jctx, 0); 2435a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 2445a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 2455a3bb1a4SNico Weber 246*6563bb53SDmitry Vyukov Acquire(thr, 0, addr); 2475a3bb1a4SNico Weber } 2485a3bb1a4SNico Weber 2495a3bb1a4SNico Weber void __tsan_java_release(jptr addr) { 2505a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_release); 2515a3bb1a4SNico Weber DPrintf("#%d: java_release(%p)\n", thr->tid, addr); 2525a3bb1a4SNico Weber CHECK_NE(jctx, 0); 2535a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 2545a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 2555a3bb1a4SNico Weber 256*6563bb53SDmitry Vyukov Release(thr, 0, addr); 2575a3bb1a4SNico Weber } 2585a3bb1a4SNico Weber 2595a3bb1a4SNico Weber void __tsan_java_release_store(jptr addr) { 2605a3bb1a4SNico Weber SCOPED_JAVA_FUNC(__tsan_java_release); 2615a3bb1a4SNico Weber DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr); 2625a3bb1a4SNico Weber CHECK_NE(jctx, 0); 2635a3bb1a4SNico Weber CHECK_GE(addr, jctx->heap_begin); 2645a3bb1a4SNico Weber CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); 2655a3bb1a4SNico Weber 266*6563bb53SDmitry Vyukov ReleaseStore(thr, 0, addr); 2675a3bb1a4SNico Weber } 268