10b57cec5SDimitry Andric//===-- wrappers_c.inc ------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric// 30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric// 70b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric#ifndef SCUDO_PREFIX 100b57cec5SDimitry Andric#error "Define SCUDO_PREFIX prior to including this file!" 110b57cec5SDimitry Andric#endif 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric// malloc-type functions have to be aligned to std::max_align_t. This is 140b57cec5SDimitry Andric// distinct from (1U << SCUDO_MIN_ALIGNMENT_LOG), since C++ new-type functions 150b57cec5SDimitry Andric// do not have to abide by the same requirement. 160b57cec5SDimitry Andric#ifndef SCUDO_MALLOC_ALIGNMENT 170b57cec5SDimitry Andric#define SCUDO_MALLOC_ALIGNMENT FIRST_32_SECOND_64(8U, 16U) 180b57cec5SDimitry Andric#endif 190b57cec5SDimitry Andric 205f757f3fSDimitry Andricstatic void reportAllocation(void *ptr, size_t size) { 215f757f3fSDimitry Andric if (SCUDO_ENABLE_HOOKS) 225f757f3fSDimitry Andric if (__scudo_allocate_hook && ptr) 235f757f3fSDimitry Andric __scudo_allocate_hook(ptr, size); 245f757f3fSDimitry Andric} 255f757f3fSDimitry Andricstatic void reportDeallocation(void *ptr) { 265f757f3fSDimitry Andric if (SCUDO_ENABLE_HOOKS) 275f757f3fSDimitry Andric if (__scudo_deallocate_hook) 285f757f3fSDimitry Andric __scudo_deallocate_hook(ptr); 295f757f3fSDimitry Andric} 305f757f3fSDimitry Andricstatic void reportReallocAllocation(void *old_ptr, void *new_ptr, size_t size) { 315f757f3fSDimitry Andric DCHECK_NE(new_ptr, nullptr); 325f757f3fSDimitry Andric 335f757f3fSDimitry Andric if (SCUDO_ENABLE_HOOKS) { 345f757f3fSDimitry Andric if (__scudo_realloc_allocate_hook) 355f757f3fSDimitry Andric __scudo_realloc_allocate_hook(old_ptr, new_ptr, size); 365f757f3fSDimitry Andric else if (__scudo_allocate_hook) 375f757f3fSDimitry Andric __scudo_allocate_hook(new_ptr, size); 385f757f3fSDimitry Andric } 395f757f3fSDimitry Andric} 405f757f3fSDimitry Andricstatic void reportReallocDeallocation(void *old_ptr) { 415f757f3fSDimitry Andric if (SCUDO_ENABLE_HOOKS) { 425f757f3fSDimitry Andric if (__scudo_realloc_deallocate_hook) 435f757f3fSDimitry Andric __scudo_realloc_deallocate_hook(old_ptr); 445f757f3fSDimitry Andric else if (__scudo_deallocate_hook) 455f757f3fSDimitry Andric __scudo_deallocate_hook(old_ptr); 465f757f3fSDimitry Andric } 475f757f3fSDimitry Andric} 485f757f3fSDimitry Andric 49480093f4SDimitry Andricextern "C" { 50480093f4SDimitry Andric 510b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(calloc)(size_t nmemb, size_t size) { 520b57cec5SDimitry Andric scudo::uptr Product; 530b57cec5SDimitry Andric if (UNLIKELY(scudo::checkForCallocOverflow(size, nmemb, &Product))) { 540b57cec5SDimitry Andric if (SCUDO_ALLOCATOR.canReturnNull()) { 550b57cec5SDimitry Andric errno = ENOMEM; 560b57cec5SDimitry Andric return nullptr; 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric scudo::reportCallocOverflow(nmemb, size); 590b57cec5SDimitry Andric } 605f757f3fSDimitry Andric void *Ptr = SCUDO_ALLOCATOR.allocate(Product, scudo::Chunk::Origin::Malloc, 615f757f3fSDimitry Andric SCUDO_MALLOC_ALIGNMENT, true); 625f757f3fSDimitry Andric reportAllocation(Ptr, Product); 635f757f3fSDimitry Andric return scudo::setErrnoOnNull(Ptr); 640b57cec5SDimitry Andric} 650b57cec5SDimitry Andric 660b57cec5SDimitry AndricINTERFACE WEAK void SCUDO_PREFIX(free)(void *ptr) { 675f757f3fSDimitry Andric reportDeallocation(ptr); 680b57cec5SDimitry Andric SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc); 690b57cec5SDimitry Andric} 700b57cec5SDimitry Andric 710b57cec5SDimitry AndricINTERFACE WEAK struct SCUDO_MALLINFO SCUDO_PREFIX(mallinfo)(void) { 720b57cec5SDimitry Andric struct SCUDO_MALLINFO Info = {}; 730b57cec5SDimitry Andric scudo::StatCounters Stats; 740b57cec5SDimitry Andric SCUDO_ALLOCATOR.getStats(Stats); 7568d75effSDimitry Andric // Space allocated in mmapped regions (bytes) 7668d75effSDimitry Andric Info.hblkhd = static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatMapped]); 7768d75effSDimitry Andric // Maximum total allocated space (bytes) 7868d75effSDimitry Andric Info.usmblks = Info.hblkhd; 7968d75effSDimitry Andric // Space in freed fastbin blocks (bytes) 8068d75effSDimitry Andric Info.fsmblks = static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatFree]); 8168d75effSDimitry Andric // Total allocated space (bytes) 820b57cec5SDimitry Andric Info.uordblks = 830b57cec5SDimitry Andric static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatAllocated]); 8468d75effSDimitry Andric // Total free space (bytes) 8568d75effSDimitry Andric Info.fordblks = Info.fsmblks; 860b57cec5SDimitry Andric return Info; 870b57cec5SDimitry Andric} 880b57cec5SDimitry Andric 8906c3fb27SDimitry Andric// On Android, mallinfo2 is an alias of mallinfo, so don't define both. 9006c3fb27SDimitry Andric#if !SCUDO_ANDROID 91349cc55cSDimitry AndricINTERFACE WEAK struct __scudo_mallinfo2 SCUDO_PREFIX(mallinfo2)(void) { 92349cc55cSDimitry Andric struct __scudo_mallinfo2 Info = {}; 93349cc55cSDimitry Andric scudo::StatCounters Stats; 94349cc55cSDimitry Andric SCUDO_ALLOCATOR.getStats(Stats); 95349cc55cSDimitry Andric // Space allocated in mmapped regions (bytes) 96349cc55cSDimitry Andric Info.hblkhd = Stats[scudo::StatMapped]; 97349cc55cSDimitry Andric // Maximum total allocated space (bytes) 98349cc55cSDimitry Andric Info.usmblks = Info.hblkhd; 99349cc55cSDimitry Andric // Space in freed fastbin blocks (bytes) 100349cc55cSDimitry Andric Info.fsmblks = Stats[scudo::StatFree]; 101349cc55cSDimitry Andric // Total allocated space (bytes) 102349cc55cSDimitry Andric Info.uordblks = Stats[scudo::StatAllocated]; 103349cc55cSDimitry Andric // Total free space (bytes) 104349cc55cSDimitry Andric Info.fordblks = Info.fsmblks; 105349cc55cSDimitry Andric return Info; 106349cc55cSDimitry Andric} 10706c3fb27SDimitry Andric#endif 108349cc55cSDimitry Andric 1090b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(malloc)(size_t size) { 1105f757f3fSDimitry Andric void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, 1115f757f3fSDimitry Andric SCUDO_MALLOC_ALIGNMENT); 1125f757f3fSDimitry Andric reportAllocation(Ptr, size); 1135f757f3fSDimitry Andric return scudo::setErrnoOnNull(Ptr); 1140b57cec5SDimitry Andric} 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric#if SCUDO_ANDROID 1170b57cec5SDimitry AndricINTERFACE WEAK size_t SCUDO_PREFIX(malloc_usable_size)(const void *ptr) { 1180b57cec5SDimitry Andric#else 1190b57cec5SDimitry AndricINTERFACE WEAK size_t SCUDO_PREFIX(malloc_usable_size)(void *ptr) { 1200b57cec5SDimitry Andric#endif 1210b57cec5SDimitry Andric return SCUDO_ALLOCATOR.getUsableSize(ptr); 1220b57cec5SDimitry Andric} 1230b57cec5SDimitry Andric 1240b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(memalign)(size_t alignment, size_t size) { 1250b57cec5SDimitry Andric // Android rounds up the alignment to a power of two if it isn't one. 1260b57cec5SDimitry Andric if (SCUDO_ANDROID) { 1270b57cec5SDimitry Andric if (UNLIKELY(!alignment)) { 1280b57cec5SDimitry Andric alignment = 1U; 1290b57cec5SDimitry Andric } else { 1300b57cec5SDimitry Andric if (UNLIKELY(!scudo::isPowerOfTwo(alignment))) 13106c3fb27SDimitry Andric alignment = scudo::roundUpPowerOfTwo(alignment); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric } else { 1340b57cec5SDimitry Andric if (UNLIKELY(!scudo::isPowerOfTwo(alignment))) { 1350b57cec5SDimitry Andric if (SCUDO_ALLOCATOR.canReturnNull()) { 1360b57cec5SDimitry Andric errno = EINVAL; 1370b57cec5SDimitry Andric return nullptr; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric scudo::reportAlignmentNotPowerOfTwo(alignment); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric } 1425f757f3fSDimitry Andric void *Ptr = 1435f757f3fSDimitry Andric SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment); 1445f757f3fSDimitry Andric reportAllocation(Ptr, size); 1455f757f3fSDimitry Andric return Ptr; 1460b57cec5SDimitry Andric} 1470b57cec5SDimitry Andric 1480b57cec5SDimitry AndricINTERFACE WEAK int SCUDO_PREFIX(posix_memalign)(void **memptr, size_t alignment, 1490b57cec5SDimitry Andric size_t size) { 1500b57cec5SDimitry Andric if (UNLIKELY(scudo::checkPosixMemalignAlignment(alignment))) { 1510b57cec5SDimitry Andric if (!SCUDO_ALLOCATOR.canReturnNull()) 1520b57cec5SDimitry Andric scudo::reportInvalidPosixMemalignAlignment(alignment); 1530b57cec5SDimitry Andric return EINVAL; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric void *Ptr = 1560b57cec5SDimitry Andric SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment); 1570b57cec5SDimitry Andric if (UNLIKELY(!Ptr)) 1580b57cec5SDimitry Andric return ENOMEM; 1595f757f3fSDimitry Andric reportAllocation(Ptr, size); 1605f757f3fSDimitry Andric 1610b57cec5SDimitry Andric *memptr = Ptr; 1620b57cec5SDimitry Andric return 0; 1630b57cec5SDimitry Andric} 1640b57cec5SDimitry Andric 1650b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(pvalloc)(size_t size) { 1660b57cec5SDimitry Andric const scudo::uptr PageSize = scudo::getPageSizeCached(); 1670b57cec5SDimitry Andric if (UNLIKELY(scudo::checkForPvallocOverflow(size, PageSize))) { 1680b57cec5SDimitry Andric if (SCUDO_ALLOCATOR.canReturnNull()) { 1690b57cec5SDimitry Andric errno = ENOMEM; 1700b57cec5SDimitry Andric return nullptr; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric scudo::reportPvallocOverflow(size); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric // pvalloc(0) should allocate one page. 1755f757f3fSDimitry Andric void *Ptr = 17606c3fb27SDimitry Andric SCUDO_ALLOCATOR.allocate(size ? scudo::roundUp(size, PageSize) : PageSize, 1775f757f3fSDimitry Andric scudo::Chunk::Origin::Memalign, PageSize); 1785f757f3fSDimitry Andric reportAllocation(Ptr, scudo::roundUp(size, PageSize)); 1795f757f3fSDimitry Andric 1805f757f3fSDimitry Andric return scudo::setErrnoOnNull(Ptr); 1810b57cec5SDimitry Andric} 1820b57cec5SDimitry Andric 1830b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(realloc)(void *ptr, size_t size) { 1845f757f3fSDimitry Andric if (!ptr) { 1855f757f3fSDimitry Andric void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, 1865f757f3fSDimitry Andric SCUDO_MALLOC_ALIGNMENT); 1875f757f3fSDimitry Andric reportAllocation(Ptr, size); 1885f757f3fSDimitry Andric return scudo::setErrnoOnNull(Ptr); 1895f757f3fSDimitry Andric } 1900b57cec5SDimitry Andric if (size == 0) { 1915f757f3fSDimitry Andric reportDeallocation(ptr); 1920b57cec5SDimitry Andric SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc); 1930b57cec5SDimitry Andric return nullptr; 1940b57cec5SDimitry Andric } 1955f757f3fSDimitry Andric 1965f757f3fSDimitry Andric // Given that the reporting of deallocation and allocation are not atomic, we 1975f757f3fSDimitry Andric // always pretend the old pointer will be released so that the user doesn't 1985f757f3fSDimitry Andric // need to worry about the false double-use case from the view of hooks. 1995f757f3fSDimitry Andric // 2005f757f3fSDimitry Andric // For example, assume that `realloc` releases the old pointer and allocates a 2015f757f3fSDimitry Andric // new pointer. Before the reporting of both operations has been done, another 2025f757f3fSDimitry Andric // thread may get the old pointer from `malloc`. It may be misinterpreted as 2035f757f3fSDimitry Andric // double-use if it's not handled properly on the hook side. 2045f757f3fSDimitry Andric reportReallocDeallocation(ptr); 2055f757f3fSDimitry Andric void *NewPtr = SCUDO_ALLOCATOR.reallocate(ptr, size, SCUDO_MALLOC_ALIGNMENT); 2065f757f3fSDimitry Andric if (NewPtr != nullptr) { 2075f757f3fSDimitry Andric // Note that even if NewPtr == ptr, the size has changed. We still need to 2085f757f3fSDimitry Andric // report the new size. 2095f757f3fSDimitry Andric reportReallocAllocation(/*OldPtr=*/ptr, NewPtr, size); 2105f757f3fSDimitry Andric } else { 2115f757f3fSDimitry Andric // If `realloc` fails, the old pointer is not released. Report the old 2125f757f3fSDimitry Andric // pointer as allocated again. 2135f757f3fSDimitry Andric reportReallocAllocation(/*OldPtr=*/ptr, /*NewPtr=*/ptr, 2145f757f3fSDimitry Andric SCUDO_ALLOCATOR.getAllocSize(ptr)); 2155f757f3fSDimitry Andric } 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric return scudo::setErrnoOnNull(NewPtr); 2180b57cec5SDimitry Andric} 2190b57cec5SDimitry Andric 2200b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(valloc)(size_t size) { 2215f757f3fSDimitry Andric void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, 2225f757f3fSDimitry Andric scudo::getPageSizeCached()); 2235f757f3fSDimitry Andric reportAllocation(Ptr, size); 2245f757f3fSDimitry Andric 2255f757f3fSDimitry Andric return scudo::setErrnoOnNull(Ptr); 2260b57cec5SDimitry Andric} 2270b57cec5SDimitry Andric 228480093f4SDimitry AndricINTERFACE WEAK int SCUDO_PREFIX(malloc_iterate)( 2290b57cec5SDimitry Andric uintptr_t base, size_t size, 2300b57cec5SDimitry Andric void (*callback)(uintptr_t base, size_t size, void *arg), void *arg) { 2310b57cec5SDimitry Andric SCUDO_ALLOCATOR.iterateOverChunks(base, size, callback, arg); 2320b57cec5SDimitry Andric return 0; 2330b57cec5SDimitry Andric} 2340b57cec5SDimitry Andric 235480093f4SDimitry AndricINTERFACE WEAK void SCUDO_PREFIX(malloc_enable)() { SCUDO_ALLOCATOR.enable(); } 236480093f4SDimitry Andric 2370b57cec5SDimitry AndricINTERFACE WEAK void SCUDO_PREFIX(malloc_disable)() { 2380b57cec5SDimitry Andric SCUDO_ALLOCATOR.disable(); 2390b57cec5SDimitry Andric} 2400b57cec5SDimitry Andric 241480093f4SDimitry Andricvoid SCUDO_PREFIX(malloc_postinit)() { 2425ffd83dbSDimitry Andric SCUDO_ALLOCATOR.initGwpAsan(); 243480093f4SDimitry Andric pthread_atfork(SCUDO_PREFIX(malloc_disable), SCUDO_PREFIX(malloc_enable), 244480093f4SDimitry Andric SCUDO_PREFIX(malloc_enable)); 245480093f4SDimitry Andric} 2460b57cec5SDimitry Andric 247e8d8bef9SDimitry AndricINTERFACE WEAK int SCUDO_PREFIX(mallopt)(int param, int value) { 2480b57cec5SDimitry Andric if (param == M_DECAY_TIME) { 2495ffd83dbSDimitry Andric if (SCUDO_ANDROID) { 250*0fca6ea1SDimitry Andric // Before changing the interval, reset the memory usage status by doing a 251*0fca6ea1SDimitry Andric // M_PURGE call so that we can minimize the impact of any unreleased pages 252*0fca6ea1SDimitry Andric // introduced by interval transition. 253*0fca6ea1SDimitry Andric SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::Force); 254*0fca6ea1SDimitry Andric 255*0fca6ea1SDimitry Andric // The values allowed on Android are {-1, 0, 1}. "1" means the longest 256*0fca6ea1SDimitry Andric // interval. 257*0fca6ea1SDimitry Andric CHECK(value >= -1 && value <= 1); 258*0fca6ea1SDimitry Andric if (value == 1) 2595ffd83dbSDimitry Andric value = INT32_MAX; 2605ffd83dbSDimitry Andric } 2615ffd83dbSDimitry Andric 2625ffd83dbSDimitry Andric SCUDO_ALLOCATOR.setOption(scudo::Option::ReleaseInterval, 2635ffd83dbSDimitry Andric static_cast<scudo::sptr>(value)); 2640b57cec5SDimitry Andric return 1; 2650b57cec5SDimitry Andric } else if (param == M_PURGE) { 26606c3fb27SDimitry Andric SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::Force); 26706c3fb27SDimitry Andric return 1; 26806c3fb27SDimitry Andric } else if (param == M_PURGE_ALL) { 26906c3fb27SDimitry Andric SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::ForceAll); 27006c3fb27SDimitry Andric return 1; 27106c3fb27SDimitry Andric } else if (param == M_LOG_STATS) { 27206c3fb27SDimitry Andric SCUDO_ALLOCATOR.printStats(); 2735f757f3fSDimitry Andric SCUDO_ALLOCATOR.printFragmentationInfo(); 2740b57cec5SDimitry Andric return 1; 275e8d8bef9SDimitry Andric } else { 276e8d8bef9SDimitry Andric scudo::Option option; 277e8d8bef9SDimitry Andric switch (param) { 278e8d8bef9SDimitry Andric case M_MEMTAG_TUNING: 279e8d8bef9SDimitry Andric option = scudo::Option::MemtagTuning; 280e8d8bef9SDimitry Andric break; 281e8d8bef9SDimitry Andric case M_THREAD_DISABLE_MEM_INIT: 282e8d8bef9SDimitry Andric option = scudo::Option::ThreadDisableMemInit; 283e8d8bef9SDimitry Andric break; 284e8d8bef9SDimitry Andric case M_CACHE_COUNT_MAX: 285e8d8bef9SDimitry Andric option = scudo::Option::MaxCacheEntriesCount; 286e8d8bef9SDimitry Andric break; 287e8d8bef9SDimitry Andric case M_CACHE_SIZE_MAX: 288e8d8bef9SDimitry Andric option = scudo::Option::MaxCacheEntrySize; 289e8d8bef9SDimitry Andric break; 290e8d8bef9SDimitry Andric case M_TSDS_COUNT_MAX: 291e8d8bef9SDimitry Andric option = scudo::Option::MaxTSDsCount; 292e8d8bef9SDimitry Andric break; 293e8d8bef9SDimitry Andric default: 2940b57cec5SDimitry Andric return 0; 2950b57cec5SDimitry Andric } 296e8d8bef9SDimitry Andric return SCUDO_ALLOCATOR.setOption(option, static_cast<scudo::sptr>(value)); 297e8d8bef9SDimitry Andric } 298e8d8bef9SDimitry Andric} 2990b57cec5SDimitry Andric 3000b57cec5SDimitry AndricINTERFACE WEAK void *SCUDO_PREFIX(aligned_alloc)(size_t alignment, 3010b57cec5SDimitry Andric size_t size) { 3020b57cec5SDimitry Andric if (UNLIKELY(scudo::checkAlignedAllocAlignmentAndSize(alignment, size))) { 3030b57cec5SDimitry Andric if (SCUDO_ALLOCATOR.canReturnNull()) { 3040b57cec5SDimitry Andric errno = EINVAL; 3050b57cec5SDimitry Andric return nullptr; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric scudo::reportInvalidAlignedAllocAlignment(alignment, size); 3080b57cec5SDimitry Andric } 3095f757f3fSDimitry Andric 3105f757f3fSDimitry Andric void *Ptr = 3115f757f3fSDimitry Andric SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, alignment); 3125f757f3fSDimitry Andric reportAllocation(Ptr, size); 3135f757f3fSDimitry Andric 3145f757f3fSDimitry Andric return scudo::setErrnoOnNull(Ptr); 3150b57cec5SDimitry Andric} 3160b57cec5SDimitry Andric 31768d75effSDimitry AndricINTERFACE WEAK int SCUDO_PREFIX(malloc_info)(UNUSED int options, FILE *stream) { 3185ffd83dbSDimitry Andric const scudo::uptr max_size = 3195ffd83dbSDimitry Andric decltype(SCUDO_ALLOCATOR)::PrimaryT::SizeClassMap::MaxSize; 3205ffd83dbSDimitry Andric auto *sizes = static_cast<scudo::uptr *>( 3215ffd83dbSDimitry Andric SCUDO_PREFIX(calloc)(max_size, sizeof(scudo::uptr))); 3225ffd83dbSDimitry Andric auto callback = [](uintptr_t, size_t size, void *arg) { 3235ffd83dbSDimitry Andric auto *sizes = reinterpret_cast<scudo::uptr *>(arg); 3245ffd83dbSDimitry Andric if (size < max_size) 3255ffd83dbSDimitry Andric sizes[size]++; 3265ffd83dbSDimitry Andric }; 32706c3fb27SDimitry Andric 32806c3fb27SDimitry Andric SCUDO_ALLOCATOR.disable(); 3295ffd83dbSDimitry Andric SCUDO_ALLOCATOR.iterateOverChunks(0, -1ul, callback, sizes); 33006c3fb27SDimitry Andric SCUDO_ALLOCATOR.enable(); 3315ffd83dbSDimitry Andric 3325ffd83dbSDimitry Andric fputs("<malloc version=\"scudo-1\">\n", stream); 3335ffd83dbSDimitry Andric for (scudo::uptr i = 0; i != max_size; ++i) 3345ffd83dbSDimitry Andric if (sizes[i]) 335349cc55cSDimitry Andric fprintf(stream, "<alloc size=\"%zu\" count=\"%zu\"/>\n", i, sizes[i]); 3365ffd83dbSDimitry Andric fputs("</malloc>\n", stream); 3375ffd83dbSDimitry Andric SCUDO_PREFIX(free)(sizes); 33868d75effSDimitry Andric return 0; 3390b57cec5SDimitry Andric} 340480093f4SDimitry Andric 3415ffd83dbSDimitry Andric// Disable memory tagging for the heap. The caller must disable memory tag 3425ffd83dbSDimitry Andric// checks globally (e.g. by clearing TCF0 on aarch64) before calling this 343e8d8bef9SDimitry Andric// function, and may not re-enable them after calling the function. 3445ffd83dbSDimitry AndricINTERFACE WEAK void SCUDO_PREFIX(malloc_disable_memory_tagging)() { 3455ffd83dbSDimitry Andric SCUDO_ALLOCATOR.disableMemoryTagging(); 3465ffd83dbSDimitry Andric} 3475ffd83dbSDimitry Andric 3485ffd83dbSDimitry Andric// Sets whether scudo records stack traces and other metadata for allocations 3495ffd83dbSDimitry Andric// and deallocations. This function only has an effect if the allocator and 350e8d8bef9SDimitry Andric// hardware support memory tagging. 3515ffd83dbSDimitry AndricINTERFACE WEAK void 3525ffd83dbSDimitry AndricSCUDO_PREFIX(malloc_set_track_allocation_stacks)(int track) { 3535ffd83dbSDimitry Andric SCUDO_ALLOCATOR.setTrackAllocationStacks(track); 3545ffd83dbSDimitry Andric} 3555ffd83dbSDimitry Andric 356e8d8bef9SDimitry Andric// Sets whether scudo zero-initializes all allocated memory. 3575ffd83dbSDimitry AndricINTERFACE WEAK void SCUDO_PREFIX(malloc_set_zero_contents)(int zero_contents) { 3585ffd83dbSDimitry Andric SCUDO_ALLOCATOR.setFillContents(zero_contents ? scudo::ZeroFill 3595ffd83dbSDimitry Andric : scudo::NoFill); 3605ffd83dbSDimitry Andric} 3615ffd83dbSDimitry Andric 362e8d8bef9SDimitry Andric// Sets whether scudo pattern-initializes all allocated memory. 3635ffd83dbSDimitry AndricINTERFACE WEAK void 3645ffd83dbSDimitry AndricSCUDO_PREFIX(malloc_set_pattern_fill_contents)(int pattern_fill_contents) { 3655ffd83dbSDimitry Andric SCUDO_ALLOCATOR.setFillContents( 3665ffd83dbSDimitry Andric pattern_fill_contents ? scudo::PatternOrZeroFill : scudo::NoFill); 3675ffd83dbSDimitry Andric} 3685ffd83dbSDimitry Andric 369fe6060f1SDimitry Andric// Sets whether scudo adds a small amount of slack at the end of large 370fe6060f1SDimitry Andric// allocations, before the guard page. This can be enabled to work around buggy 371fe6060f1SDimitry Andric// applications that read a few bytes past the end of their allocation. 372fe6060f1SDimitry AndricINTERFACE WEAK void 373fe6060f1SDimitry AndricSCUDO_PREFIX(malloc_set_add_large_allocation_slack)(int add_slack) { 374fe6060f1SDimitry Andric SCUDO_ALLOCATOR.setAddLargeAllocationSlack(add_slack); 375fe6060f1SDimitry Andric} 376fe6060f1SDimitry Andric 377480093f4SDimitry Andric} // extern "C" 378