168d75effSDimitry Andric //===-- tsan_mman.cpp -----------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_checks.h" 1368d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_interface.h" 1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_report.h" 1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_errno.h" 1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 1868d75effSDimitry Andric #include "tsan_mman.h" 1968d75effSDimitry Andric #include "tsan_rtl.h" 2068d75effSDimitry Andric #include "tsan_report.h" 2168d75effSDimitry Andric #include "tsan_flags.h" 2268d75effSDimitry Andric 2368d75effSDimitry Andric // May be overriden by front-end. 2468d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL 2568d75effSDimitry Andric void __sanitizer_malloc_hook(void *ptr, uptr size) { 2668d75effSDimitry Andric (void)ptr; 2768d75effSDimitry Andric (void)size; 2868d75effSDimitry Andric } 2968d75effSDimitry Andric 3068d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL 3168d75effSDimitry Andric void __sanitizer_free_hook(void *ptr) { 3268d75effSDimitry Andric (void)ptr; 3368d75effSDimitry Andric } 3468d75effSDimitry Andric 3568d75effSDimitry Andric namespace __tsan { 3668d75effSDimitry Andric 3768d75effSDimitry Andric struct MapUnmapCallback { 3868d75effSDimitry Andric void OnMap(uptr p, uptr size) const { } 3968d75effSDimitry Andric void OnUnmap(uptr p, uptr size) const { 4068d75effSDimitry Andric // We are about to unmap a chunk of user memory. 4168d75effSDimitry Andric // Mark the corresponding shadow memory as not needed. 4268d75effSDimitry Andric DontNeedShadowFor(p, size); 4368d75effSDimitry Andric // Mark the corresponding meta shadow memory as not needed. 4468d75effSDimitry Andric // Note the block does not contain any meta info at this point 4568d75effSDimitry Andric // (this happens after free). 4668d75effSDimitry Andric const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize; 4768d75effSDimitry Andric const uptr kPageSize = GetPageSizeCached() * kMetaRatio; 4868d75effSDimitry Andric // Block came from LargeMmapAllocator, so must be large. 4968d75effSDimitry Andric // We rely on this in the calculations below. 5068d75effSDimitry Andric CHECK_GE(size, 2 * kPageSize); 5168d75effSDimitry Andric uptr diff = RoundUp(p, kPageSize) - p; 5268d75effSDimitry Andric if (diff != 0) { 5368d75effSDimitry Andric p += diff; 5468d75effSDimitry Andric size -= diff; 5568d75effSDimitry Andric } 5668d75effSDimitry Andric diff = p + size - RoundDown(p + size, kPageSize); 5768d75effSDimitry Andric if (diff != 0) 5868d75effSDimitry Andric size -= diff; 5968d75effSDimitry Andric uptr p_meta = (uptr)MemToMeta(p); 6068d75effSDimitry Andric ReleaseMemoryPagesToOS(p_meta, p_meta + size / kMetaRatio); 6168d75effSDimitry Andric } 6268d75effSDimitry Andric }; 6368d75effSDimitry Andric 6468d75effSDimitry Andric static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64); 6568d75effSDimitry Andric Allocator *allocator() { 6668d75effSDimitry Andric return reinterpret_cast<Allocator*>(&allocator_placeholder); 6768d75effSDimitry Andric } 6868d75effSDimitry Andric 6968d75effSDimitry Andric struct GlobalProc { 7068d75effSDimitry Andric Mutex mtx; 7168d75effSDimitry Andric Processor *proc; 7268d75effSDimitry Andric 7368d75effSDimitry Andric GlobalProc() 7468d75effSDimitry Andric : mtx(MutexTypeGlobalProc, StatMtxGlobalProc) 7568d75effSDimitry Andric , proc(ProcCreate()) { 7668d75effSDimitry Andric } 7768d75effSDimitry Andric }; 7868d75effSDimitry Andric 7968d75effSDimitry Andric static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64); 8068d75effSDimitry Andric GlobalProc *global_proc() { 8168d75effSDimitry Andric return reinterpret_cast<GlobalProc*>(&global_proc_placeholder); 8268d75effSDimitry Andric } 8368d75effSDimitry Andric 8468d75effSDimitry Andric ScopedGlobalProcessor::ScopedGlobalProcessor() { 8568d75effSDimitry Andric GlobalProc *gp = global_proc(); 8668d75effSDimitry Andric ThreadState *thr = cur_thread(); 8768d75effSDimitry Andric if (thr->proc()) 8868d75effSDimitry Andric return; 8968d75effSDimitry Andric // If we don't have a proc, use the global one. 9068d75effSDimitry Andric // There are currently only two known case where this path is triggered: 9168d75effSDimitry Andric // __interceptor_free 9268d75effSDimitry Andric // __nptl_deallocate_tsd 9368d75effSDimitry Andric // start_thread 9468d75effSDimitry Andric // clone 9568d75effSDimitry Andric // and: 9668d75effSDimitry Andric // ResetRange 9768d75effSDimitry Andric // __interceptor_munmap 9868d75effSDimitry Andric // __deallocate_stack 9968d75effSDimitry Andric // start_thread 10068d75effSDimitry Andric // clone 10168d75effSDimitry Andric // Ideally, we destroy thread state (and unwire proc) when a thread actually 10268d75effSDimitry Andric // exits (i.e. when we join/wait it). Then we would not need the global proc 10368d75effSDimitry Andric gp->mtx.Lock(); 10468d75effSDimitry Andric ProcWire(gp->proc, thr); 10568d75effSDimitry Andric } 10668d75effSDimitry Andric 10768d75effSDimitry Andric ScopedGlobalProcessor::~ScopedGlobalProcessor() { 10868d75effSDimitry Andric GlobalProc *gp = global_proc(); 10968d75effSDimitry Andric ThreadState *thr = cur_thread(); 11068d75effSDimitry Andric if (thr->proc() != gp->proc) 11168d75effSDimitry Andric return; 11268d75effSDimitry Andric ProcUnwire(gp->proc, thr); 11368d75effSDimitry Andric gp->mtx.Unlock(); 11468d75effSDimitry Andric } 11568d75effSDimitry Andric 116*480093f4SDimitry Andric static constexpr uptr kMaxAllowedMallocSize = 1ull << 40; 117*480093f4SDimitry Andric static uptr max_user_defined_malloc_size; 118*480093f4SDimitry Andric 11968d75effSDimitry Andric void InitializeAllocator() { 12068d75effSDimitry Andric SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); 12168d75effSDimitry Andric allocator()->Init(common_flags()->allocator_release_to_os_interval_ms); 122*480093f4SDimitry Andric max_user_defined_malloc_size = common_flags()->max_allocation_size_mb 123*480093f4SDimitry Andric ? common_flags()->max_allocation_size_mb 124*480093f4SDimitry Andric << 20 125*480093f4SDimitry Andric : kMaxAllowedMallocSize; 12668d75effSDimitry Andric } 12768d75effSDimitry Andric 12868d75effSDimitry Andric void InitializeAllocatorLate() { 12968d75effSDimitry Andric new(global_proc()) GlobalProc(); 13068d75effSDimitry Andric } 13168d75effSDimitry Andric 13268d75effSDimitry Andric void AllocatorProcStart(Processor *proc) { 13368d75effSDimitry Andric allocator()->InitCache(&proc->alloc_cache); 13468d75effSDimitry Andric internal_allocator()->InitCache(&proc->internal_alloc_cache); 13568d75effSDimitry Andric } 13668d75effSDimitry Andric 13768d75effSDimitry Andric void AllocatorProcFinish(Processor *proc) { 13868d75effSDimitry Andric allocator()->DestroyCache(&proc->alloc_cache); 13968d75effSDimitry Andric internal_allocator()->DestroyCache(&proc->internal_alloc_cache); 14068d75effSDimitry Andric } 14168d75effSDimitry Andric 14268d75effSDimitry Andric void AllocatorPrintStats() { 14368d75effSDimitry Andric allocator()->PrintStats(); 14468d75effSDimitry Andric } 14568d75effSDimitry Andric 14668d75effSDimitry Andric static void SignalUnsafeCall(ThreadState *thr, uptr pc) { 14768d75effSDimitry Andric if (atomic_load_relaxed(&thr->in_signal_handler) == 0 || 14868d75effSDimitry Andric !flags()->report_signal_unsafe) 14968d75effSDimitry Andric return; 15068d75effSDimitry Andric VarSizeStackTrace stack; 15168d75effSDimitry Andric ObtainCurrentStack(thr, pc, &stack); 15268d75effSDimitry Andric if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack)) 15368d75effSDimitry Andric return; 15468d75effSDimitry Andric ThreadRegistryLock l(ctx->thread_registry); 15568d75effSDimitry Andric ScopedReport rep(ReportTypeSignalUnsafe); 15668d75effSDimitry Andric rep.AddStack(stack, true); 15768d75effSDimitry Andric OutputReport(thr, rep); 15868d75effSDimitry Andric } 15968d75effSDimitry Andric 16068d75effSDimitry Andric 16168d75effSDimitry Andric void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align, 16268d75effSDimitry Andric bool signal) { 163*480093f4SDimitry Andric if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize || 164*480093f4SDimitry Andric sz > max_user_defined_malloc_size) { 16568d75effSDimitry Andric if (AllocatorMayReturnNull()) 16668d75effSDimitry Andric return nullptr; 167*480093f4SDimitry Andric uptr malloc_limit = 168*480093f4SDimitry Andric Min(kMaxAllowedMallocSize, max_user_defined_malloc_size); 16968d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 170*480093f4SDimitry Andric ReportAllocationSizeTooBig(sz, malloc_limit, &stack); 17168d75effSDimitry Andric } 17268d75effSDimitry Andric void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); 17368d75effSDimitry Andric if (UNLIKELY(!p)) { 17468d75effSDimitry Andric SetAllocatorOutOfMemory(); 17568d75effSDimitry Andric if (AllocatorMayReturnNull()) 17668d75effSDimitry Andric return nullptr; 17768d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 17868d75effSDimitry Andric ReportOutOfMemory(sz, &stack); 17968d75effSDimitry Andric } 18068d75effSDimitry Andric if (ctx && ctx->initialized) 18168d75effSDimitry Andric OnUserAlloc(thr, pc, (uptr)p, sz, true); 18268d75effSDimitry Andric if (signal) 18368d75effSDimitry Andric SignalUnsafeCall(thr, pc); 18468d75effSDimitry Andric return p; 18568d75effSDimitry Andric } 18668d75effSDimitry Andric 18768d75effSDimitry Andric void user_free(ThreadState *thr, uptr pc, void *p, bool signal) { 18868d75effSDimitry Andric ScopedGlobalProcessor sgp; 18968d75effSDimitry Andric if (ctx && ctx->initialized) 19068d75effSDimitry Andric OnUserFree(thr, pc, (uptr)p, true); 19168d75effSDimitry Andric allocator()->Deallocate(&thr->proc()->alloc_cache, p); 19268d75effSDimitry Andric if (signal) 19368d75effSDimitry Andric SignalUnsafeCall(thr, pc); 19468d75effSDimitry Andric } 19568d75effSDimitry Andric 19668d75effSDimitry Andric void *user_alloc(ThreadState *thr, uptr pc, uptr sz) { 19768d75effSDimitry Andric return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, kDefaultAlignment)); 19868d75effSDimitry Andric } 19968d75effSDimitry Andric 20068d75effSDimitry Andric void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { 20168d75effSDimitry Andric if (UNLIKELY(CheckForCallocOverflow(size, n))) { 20268d75effSDimitry Andric if (AllocatorMayReturnNull()) 20368d75effSDimitry Andric return SetErrnoOnNull(nullptr); 20468d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 20568d75effSDimitry Andric ReportCallocOverflow(n, size, &stack); 20668d75effSDimitry Andric } 20768d75effSDimitry Andric void *p = user_alloc_internal(thr, pc, n * size); 20868d75effSDimitry Andric if (p) 20968d75effSDimitry Andric internal_memset(p, 0, n * size); 21068d75effSDimitry Andric return SetErrnoOnNull(p); 21168d75effSDimitry Andric } 21268d75effSDimitry Andric 21368d75effSDimitry Andric void *user_reallocarray(ThreadState *thr, uptr pc, void *p, uptr size, uptr n) { 21468d75effSDimitry Andric if (UNLIKELY(CheckForCallocOverflow(size, n))) { 21568d75effSDimitry Andric if (AllocatorMayReturnNull()) 21668d75effSDimitry Andric return SetErrnoOnNull(nullptr); 21768d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 21868d75effSDimitry Andric ReportReallocArrayOverflow(size, n, &stack); 21968d75effSDimitry Andric } 22068d75effSDimitry Andric return user_realloc(thr, pc, p, size * n); 22168d75effSDimitry Andric } 22268d75effSDimitry Andric 22368d75effSDimitry Andric void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) { 22468d75effSDimitry Andric DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p); 22568d75effSDimitry Andric ctx->metamap.AllocBlock(thr, pc, p, sz); 22668d75effSDimitry Andric if (write && thr->ignore_reads_and_writes == 0) 22768d75effSDimitry Andric MemoryRangeImitateWrite(thr, pc, (uptr)p, sz); 22868d75effSDimitry Andric else 22968d75effSDimitry Andric MemoryResetRange(thr, pc, (uptr)p, sz); 23068d75effSDimitry Andric } 23168d75effSDimitry Andric 23268d75effSDimitry Andric void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) { 23368d75effSDimitry Andric CHECK_NE(p, (void*)0); 23468d75effSDimitry Andric uptr sz = ctx->metamap.FreeBlock(thr->proc(), p); 23568d75effSDimitry Andric DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz); 23668d75effSDimitry Andric if (write && thr->ignore_reads_and_writes == 0) 23768d75effSDimitry Andric MemoryRangeFreed(thr, pc, (uptr)p, sz); 23868d75effSDimitry Andric } 23968d75effSDimitry Andric 24068d75effSDimitry Andric void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) { 24168d75effSDimitry Andric // FIXME: Handle "shrinking" more efficiently, 24268d75effSDimitry Andric // it seems that some software actually does this. 24368d75effSDimitry Andric if (!p) 24468d75effSDimitry Andric return SetErrnoOnNull(user_alloc_internal(thr, pc, sz)); 24568d75effSDimitry Andric if (!sz) { 24668d75effSDimitry Andric user_free(thr, pc, p); 24768d75effSDimitry Andric return nullptr; 24868d75effSDimitry Andric } 24968d75effSDimitry Andric void *new_p = user_alloc_internal(thr, pc, sz); 25068d75effSDimitry Andric if (new_p) { 25168d75effSDimitry Andric uptr old_sz = user_alloc_usable_size(p); 25268d75effSDimitry Andric internal_memcpy(new_p, p, min(old_sz, sz)); 25368d75effSDimitry Andric user_free(thr, pc, p); 25468d75effSDimitry Andric } 25568d75effSDimitry Andric return SetErrnoOnNull(new_p); 25668d75effSDimitry Andric } 25768d75effSDimitry Andric 25868d75effSDimitry Andric void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) { 25968d75effSDimitry Andric if (UNLIKELY(!IsPowerOfTwo(align))) { 26068d75effSDimitry Andric errno = errno_EINVAL; 26168d75effSDimitry Andric if (AllocatorMayReturnNull()) 26268d75effSDimitry Andric return nullptr; 26368d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 26468d75effSDimitry Andric ReportInvalidAllocationAlignment(align, &stack); 26568d75effSDimitry Andric } 26668d75effSDimitry Andric return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); 26768d75effSDimitry Andric } 26868d75effSDimitry Andric 26968d75effSDimitry Andric int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, 27068d75effSDimitry Andric uptr sz) { 27168d75effSDimitry Andric if (UNLIKELY(!CheckPosixMemalignAlignment(align))) { 27268d75effSDimitry Andric if (AllocatorMayReturnNull()) 27368d75effSDimitry Andric return errno_EINVAL; 27468d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 27568d75effSDimitry Andric ReportInvalidPosixMemalignAlignment(align, &stack); 27668d75effSDimitry Andric } 27768d75effSDimitry Andric void *ptr = user_alloc_internal(thr, pc, sz, align); 27868d75effSDimitry Andric if (UNLIKELY(!ptr)) 27968d75effSDimitry Andric // OOM error is already taken care of by user_alloc_internal. 28068d75effSDimitry Andric return errno_ENOMEM; 28168d75effSDimitry Andric CHECK(IsAligned((uptr)ptr, align)); 28268d75effSDimitry Andric *memptr = ptr; 28368d75effSDimitry Andric return 0; 28468d75effSDimitry Andric } 28568d75effSDimitry Andric 28668d75effSDimitry Andric void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) { 28768d75effSDimitry Andric if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) { 28868d75effSDimitry Andric errno = errno_EINVAL; 28968d75effSDimitry Andric if (AllocatorMayReturnNull()) 29068d75effSDimitry Andric return nullptr; 29168d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 29268d75effSDimitry Andric ReportInvalidAlignedAllocAlignment(sz, align, &stack); 29368d75effSDimitry Andric } 29468d75effSDimitry Andric return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); 29568d75effSDimitry Andric } 29668d75effSDimitry Andric 29768d75effSDimitry Andric void *user_valloc(ThreadState *thr, uptr pc, uptr sz) { 29868d75effSDimitry Andric return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, GetPageSizeCached())); 29968d75effSDimitry Andric } 30068d75effSDimitry Andric 30168d75effSDimitry Andric void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) { 30268d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 30368d75effSDimitry Andric if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) { 30468d75effSDimitry Andric errno = errno_ENOMEM; 30568d75effSDimitry Andric if (AllocatorMayReturnNull()) 30668d75effSDimitry Andric return nullptr; 30768d75effSDimitry Andric GET_STACK_TRACE_FATAL(thr, pc); 30868d75effSDimitry Andric ReportPvallocOverflow(sz, &stack); 30968d75effSDimitry Andric } 31068d75effSDimitry Andric // pvalloc(0) should allocate one page. 31168d75effSDimitry Andric sz = sz ? RoundUpTo(sz, PageSize) : PageSize; 31268d75effSDimitry Andric return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize)); 31368d75effSDimitry Andric } 31468d75effSDimitry Andric 31568d75effSDimitry Andric uptr user_alloc_usable_size(const void *p) { 31668d75effSDimitry Andric if (p == 0) 31768d75effSDimitry Andric return 0; 31868d75effSDimitry Andric MBlock *b = ctx->metamap.GetBlock((uptr)p); 31968d75effSDimitry Andric if (!b) 32068d75effSDimitry Andric return 0; // Not a valid pointer. 32168d75effSDimitry Andric if (b->siz == 0) 32268d75effSDimitry Andric return 1; // Zero-sized allocations are actually 1 byte. 32368d75effSDimitry Andric return b->siz; 32468d75effSDimitry Andric } 32568d75effSDimitry Andric 32668d75effSDimitry Andric void invoke_malloc_hook(void *ptr, uptr size) { 32768d75effSDimitry Andric ThreadState *thr = cur_thread(); 32868d75effSDimitry Andric if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors) 32968d75effSDimitry Andric return; 33068d75effSDimitry Andric __sanitizer_malloc_hook(ptr, size); 33168d75effSDimitry Andric RunMallocHooks(ptr, size); 33268d75effSDimitry Andric } 33368d75effSDimitry Andric 33468d75effSDimitry Andric void invoke_free_hook(void *ptr) { 33568d75effSDimitry Andric ThreadState *thr = cur_thread(); 33668d75effSDimitry Andric if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors) 33768d75effSDimitry Andric return; 33868d75effSDimitry Andric __sanitizer_free_hook(ptr); 33968d75effSDimitry Andric RunFreeHooks(ptr); 34068d75effSDimitry Andric } 34168d75effSDimitry Andric 34268d75effSDimitry Andric void *internal_alloc(MBlockType typ, uptr sz) { 34368d75effSDimitry Andric ThreadState *thr = cur_thread(); 34468d75effSDimitry Andric if (thr->nomalloc) { 34568d75effSDimitry Andric thr->nomalloc = 0; // CHECK calls internal_malloc(). 34668d75effSDimitry Andric CHECK(0); 34768d75effSDimitry Andric } 34868d75effSDimitry Andric return InternalAlloc(sz, &thr->proc()->internal_alloc_cache); 34968d75effSDimitry Andric } 35068d75effSDimitry Andric 35168d75effSDimitry Andric void internal_free(void *p) { 35268d75effSDimitry Andric ThreadState *thr = cur_thread(); 35368d75effSDimitry Andric if (thr->nomalloc) { 35468d75effSDimitry Andric thr->nomalloc = 0; // CHECK calls internal_malloc(). 35568d75effSDimitry Andric CHECK(0); 35668d75effSDimitry Andric } 35768d75effSDimitry Andric InternalFree(p, &thr->proc()->internal_alloc_cache); 35868d75effSDimitry Andric } 35968d75effSDimitry Andric 36068d75effSDimitry Andric } // namespace __tsan 36168d75effSDimitry Andric 36268d75effSDimitry Andric using namespace __tsan; 36368d75effSDimitry Andric 36468d75effSDimitry Andric extern "C" { 36568d75effSDimitry Andric uptr __sanitizer_get_current_allocated_bytes() { 36668d75effSDimitry Andric uptr stats[AllocatorStatCount]; 36768d75effSDimitry Andric allocator()->GetStats(stats); 36868d75effSDimitry Andric return stats[AllocatorStatAllocated]; 36968d75effSDimitry Andric } 37068d75effSDimitry Andric 37168d75effSDimitry Andric uptr __sanitizer_get_heap_size() { 37268d75effSDimitry Andric uptr stats[AllocatorStatCount]; 37368d75effSDimitry Andric allocator()->GetStats(stats); 37468d75effSDimitry Andric return stats[AllocatorStatMapped]; 37568d75effSDimitry Andric } 37668d75effSDimitry Andric 37768d75effSDimitry Andric uptr __sanitizer_get_free_bytes() { 37868d75effSDimitry Andric return 1; 37968d75effSDimitry Andric } 38068d75effSDimitry Andric 38168d75effSDimitry Andric uptr __sanitizer_get_unmapped_bytes() { 38268d75effSDimitry Andric return 1; 38368d75effSDimitry Andric } 38468d75effSDimitry Andric 38568d75effSDimitry Andric uptr __sanitizer_get_estimated_allocated_size(uptr size) { 38668d75effSDimitry Andric return size; 38768d75effSDimitry Andric } 38868d75effSDimitry Andric 38968d75effSDimitry Andric int __sanitizer_get_ownership(const void *p) { 39068d75effSDimitry Andric return allocator()->GetBlockBegin(p) != 0; 39168d75effSDimitry Andric } 39268d75effSDimitry Andric 39368d75effSDimitry Andric uptr __sanitizer_get_allocated_size(const void *p) { 39468d75effSDimitry Andric return user_alloc_usable_size(p); 39568d75effSDimitry Andric } 39668d75effSDimitry Andric 39768d75effSDimitry Andric void __tsan_on_thread_idle() { 39868d75effSDimitry Andric ThreadState *thr = cur_thread(); 39968d75effSDimitry Andric thr->clock.ResetCached(&thr->proc()->clock_cache); 40068d75effSDimitry Andric thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); 40168d75effSDimitry Andric allocator()->SwallowCache(&thr->proc()->alloc_cache); 40268d75effSDimitry Andric internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache); 40368d75effSDimitry Andric ctx->metamap.OnProcIdle(thr->proc()); 40468d75effSDimitry Andric } 40568d75effSDimitry Andric } // extern "C" 406