123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- //===-- wrappers_c.inc ------------------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef SCUDO_PREFIX
- #error "Define SCUDO_PREFIX prior to including this file!"
- #endif
- // malloc-type functions have to be aligned to std::max_align_t. This is
- // distinct from (1U << SCUDO_MIN_ALIGNMENT_LOG), since C++ new-type functions
- // do not have to abide by the same requirement.
- #ifndef SCUDO_MALLOC_ALIGNMENT
- #define SCUDO_MALLOC_ALIGNMENT FIRST_32_SECOND_64(8U, 16U)
- #endif
- static void reportAllocation(void *ptr, size_t size) {
- if (SCUDO_ENABLE_HOOKS)
- if (__scudo_allocate_hook && ptr)
- __scudo_allocate_hook(ptr, size);
- }
- static void reportDeallocation(void *ptr) {
- if (SCUDO_ENABLE_HOOKS)
- if (__scudo_deallocate_hook)
- __scudo_deallocate_hook(ptr);
- }
- static void reportReallocAllocation(void *old_ptr, void *new_ptr, size_t size) {
- DCHECK_NE(new_ptr, nullptr);
- if (SCUDO_ENABLE_HOOKS) {
- if (__scudo_realloc_allocate_hook)
- __scudo_realloc_allocate_hook(old_ptr, new_ptr, size);
- else if (__scudo_allocate_hook)
- __scudo_allocate_hook(new_ptr, size);
- }
- }
- static void reportReallocDeallocation(void *old_ptr) {
- if (SCUDO_ENABLE_HOOKS) {
- if (__scudo_realloc_deallocate_hook)
- __scudo_realloc_deallocate_hook(old_ptr);
- else if (__scudo_deallocate_hook)
- __scudo_deallocate_hook(old_ptr);
- }
- }
- extern "C" {
- INTERFACE WEAK void *SCUDO_PREFIX(calloc)(size_t nmemb, size_t size) {
- scudo::uptr Product;
- if (UNLIKELY(scudo::checkForCallocOverflow(size, nmemb, &Product))) {
- if (SCUDO_ALLOCATOR.canReturnNull()) {
- errno = ENOMEM;
- return nullptr;
- }
- scudo::reportCallocOverflow(nmemb, size);
- }
- void *Ptr = SCUDO_ALLOCATOR.allocate(Product, scudo::Chunk::Origin::Malloc,
- SCUDO_MALLOC_ALIGNMENT, true);
- reportAllocation(Ptr, Product);
- return scudo::setErrnoOnNull(Ptr);
- }
- INTERFACE WEAK void SCUDO_PREFIX(free)(void *ptr) {
- reportDeallocation(ptr);
- SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc);
- }
- INTERFACE WEAK struct SCUDO_MALLINFO SCUDO_PREFIX(mallinfo)(void) {
- struct SCUDO_MALLINFO Info = {};
- scudo::StatCounters Stats;
- SCUDO_ALLOCATOR.getStats(Stats);
- // Space allocated in mmapped regions (bytes)
- Info.hblkhd = static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatMapped]);
- // Maximum total allocated space (bytes)
- Info.usmblks = Info.hblkhd;
- // Space in freed fastbin blocks (bytes)
- Info.fsmblks = static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatFree]);
- // Total allocated space (bytes)
- Info.uordblks =
- static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatAllocated]);
- // Total free space (bytes)
- Info.fordblks = Info.fsmblks;
- return Info;
- }
- // On Android, mallinfo2 is an alias of mallinfo, so don't define both.
- #if !SCUDO_ANDROID
- INTERFACE WEAK struct __scudo_mallinfo2 SCUDO_PREFIX(mallinfo2)(void) {
- struct __scudo_mallinfo2 Info = {};
- scudo::StatCounters Stats;
- SCUDO_ALLOCATOR.getStats(Stats);
- // Space allocated in mmapped regions (bytes)
- Info.hblkhd = Stats[scudo::StatMapped];
- // Maximum total allocated space (bytes)
- Info.usmblks = Info.hblkhd;
- // Space in freed fastbin blocks (bytes)
- Info.fsmblks = Stats[scudo::StatFree];
- // Total allocated space (bytes)
- Info.uordblks = Stats[scudo::StatAllocated];
- // Total free space (bytes)
- Info.fordblks = Info.fsmblks;
- return Info;
- }
- #endif
- INTERFACE WEAK void *SCUDO_PREFIX(malloc)(size_t size) {
- void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc,
- SCUDO_MALLOC_ALIGNMENT);
- reportAllocation(Ptr, size);
- return scudo::setErrnoOnNull(Ptr);
- }
- #if SCUDO_ANDROID
- INTERFACE WEAK size_t SCUDO_PREFIX(malloc_usable_size)(const void *ptr) {
- #else
- INTERFACE WEAK size_t SCUDO_PREFIX(malloc_usable_size)(void *ptr) {
- #endif
- return SCUDO_ALLOCATOR.getUsableSize(ptr);
- }
- INTERFACE WEAK void *SCUDO_PREFIX(memalign)(size_t alignment, size_t size) {
- // Android rounds up the alignment to a power of two if it isn't one.
- if (SCUDO_ANDROID) {
- if (UNLIKELY(!alignment)) {
- alignment = 1U;
- } else {
- if (UNLIKELY(!scudo::isPowerOfTwo(alignment)))
- alignment = scudo::roundUpPowerOfTwo(alignment);
- }
- } else {
- if (UNLIKELY(!scudo::isPowerOfTwo(alignment))) {
- if (SCUDO_ALLOCATOR.canReturnNull()) {
- errno = EINVAL;
- return nullptr;
- }
- scudo::reportAlignmentNotPowerOfTwo(alignment);
- }
- }
- void *Ptr =
- SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment);
- reportAllocation(Ptr, size);
- return Ptr;
- }
- INTERFACE WEAK int SCUDO_PREFIX(posix_memalign)(void **memptr, size_t alignment,
- size_t size) {
- if (UNLIKELY(scudo::checkPosixMemalignAlignment(alignment))) {
- if (!SCUDO_ALLOCATOR.canReturnNull())
- scudo::reportInvalidPosixMemalignAlignment(alignment);
- return EINVAL;
- }
- void *Ptr =
- SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment);
- if (UNLIKELY(!Ptr))
- return ENOMEM;
- reportAllocation(Ptr, size);
- *memptr = Ptr;
- return 0;
- }
- INTERFACE WEAK void *SCUDO_PREFIX(pvalloc)(size_t size) {
- const scudo::uptr PageSize = scudo::getPageSizeCached();
- if (UNLIKELY(scudo::checkForPvallocOverflow(size, PageSize))) {
- if (SCUDO_ALLOCATOR.canReturnNull()) {
- errno = ENOMEM;
- return nullptr;
- }
- scudo::reportPvallocOverflow(size);
- }
- // pvalloc(0) should allocate one page.
- void *Ptr =
- SCUDO_ALLOCATOR.allocate(size ? scudo::roundUp(size, PageSize) : PageSize,
- scudo::Chunk::Origin::Memalign, PageSize);
- reportAllocation(Ptr, scudo::roundUp(size, PageSize));
- return scudo::setErrnoOnNull(Ptr);
- }
- INTERFACE WEAK void *SCUDO_PREFIX(realloc)(void *ptr, size_t size) {
- if (!ptr) {
- void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc,
- SCUDO_MALLOC_ALIGNMENT);
- reportAllocation(Ptr, size);
- return scudo::setErrnoOnNull(Ptr);
- }
- if (size == 0) {
- reportDeallocation(ptr);
- SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc);
- return nullptr;
- }
- // Given that the reporting of deallocation and allocation are not atomic, we
- // always pretend the old pointer will be released so that the user doesn't
- // need to worry about the false double-use case from the view of hooks.
- //
- // For example, assume that `realloc` releases the old pointer and allocates a
- // new pointer. Before the reporting of both operations has been done, another
- // thread may get the old pointer from `malloc`. It may be misinterpreted as
- // double-use if it's not handled properly on the hook side.
- reportReallocDeallocation(ptr);
- void *NewPtr = SCUDO_ALLOCATOR.reallocate(ptr, size, SCUDO_MALLOC_ALIGNMENT);
- if (NewPtr != nullptr) {
- // Note that even if NewPtr == ptr, the size has changed. We still need to
- // report the new size.
- reportReallocAllocation(/*OldPtr=*/ptr, NewPtr, size);
- } else {
- // If `realloc` fails, the old pointer is not released. Report the old
- // pointer as allocated again.
- reportReallocAllocation(/*OldPtr=*/ptr, /*NewPtr=*/ptr,
- SCUDO_ALLOCATOR.getAllocSize(ptr));
- }
- return scudo::setErrnoOnNull(NewPtr);
- }
- INTERFACE WEAK void *SCUDO_PREFIX(valloc)(size_t size) {
- void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign,
- scudo::getPageSizeCached());
- reportAllocation(Ptr, size);
- return scudo::setErrnoOnNull(Ptr);
- }
- INTERFACE WEAK int SCUDO_PREFIX(malloc_iterate)(
- uintptr_t base, size_t size,
- void (*callback)(uintptr_t base, size_t size, void *arg), void *arg) {
- SCUDO_ALLOCATOR.iterateOverChunks(base, size, callback, arg);
- return 0;
- }
- INTERFACE WEAK void SCUDO_PREFIX(malloc_enable)() { SCUDO_ALLOCATOR.enable(); }
- INTERFACE WEAK void SCUDO_PREFIX(malloc_disable)() {
- SCUDO_ALLOCATOR.disable();
- }
- void SCUDO_PREFIX(malloc_postinit)() {
- SCUDO_ALLOCATOR.initGwpAsan();
- pthread_atfork(SCUDO_PREFIX(malloc_disable), SCUDO_PREFIX(malloc_enable),
- SCUDO_PREFIX(malloc_enable));
- }
- INTERFACE WEAK int SCUDO_PREFIX(mallopt)(int param, int value) {
- if (param == M_DECAY_TIME) {
- if (SCUDO_ANDROID) {
- if (value == 0) {
- // Will set the release values to their minimum values.
- value = INT32_MIN;
- } else {
- // Will set the release values to their maximum values.
- value = INT32_MAX;
- }
- }
- SCUDO_ALLOCATOR.setOption(scudo::Option::ReleaseInterval,
- static_cast<scudo::sptr>(value));
- return 1;
- } else if (param == M_PURGE) {
- SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::Force);
- return 1;
- } else if (param == M_PURGE_ALL) {
- SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::ForceAll);
- return 1;
- } else if (param == M_LOG_STATS) {
- SCUDO_ALLOCATOR.printStats();
- SCUDO_ALLOCATOR.printFragmentationInfo();
- return 1;
- } else {
- scudo::Option option;
- switch (param) {
- case M_MEMTAG_TUNING:
- option = scudo::Option::MemtagTuning;
- break;
- case M_THREAD_DISABLE_MEM_INIT:
- option = scudo::Option::ThreadDisableMemInit;
- break;
- case M_CACHE_COUNT_MAX:
- option = scudo::Option::MaxCacheEntriesCount;
- break;
- case M_CACHE_SIZE_MAX:
- option = scudo::Option::MaxCacheEntrySize;
- break;
- case M_TSDS_COUNT_MAX:
- option = scudo::Option::MaxTSDsCount;
- break;
- default:
- return 0;
- }
- return SCUDO_ALLOCATOR.setOption(option, static_cast<scudo::sptr>(value));
- }
- }
- INTERFACE WEAK void *SCUDO_PREFIX(aligned_alloc)(size_t alignment,
- size_t size) {
- if (UNLIKELY(scudo::checkAlignedAllocAlignmentAndSize(alignment, size))) {
- if (SCUDO_ALLOCATOR.canReturnNull()) {
- errno = EINVAL;
- return nullptr;
- }
- scudo::reportInvalidAlignedAllocAlignment(alignment, size);
- }
- void *Ptr =
- SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, alignment);
- reportAllocation(Ptr, size);
- return scudo::setErrnoOnNull(Ptr);
- }
- INTERFACE WEAK int SCUDO_PREFIX(malloc_info)(UNUSED int options, FILE *stream) {
- const scudo::uptr max_size =
- decltype(SCUDO_ALLOCATOR)::PrimaryT::SizeClassMap::MaxSize;
- auto *sizes = static_cast<scudo::uptr *>(
- SCUDO_PREFIX(calloc)(max_size, sizeof(scudo::uptr)));
- auto callback = [](uintptr_t, size_t size, void *arg) {
- auto *sizes = reinterpret_cast<scudo::uptr *>(arg);
- if (size < max_size)
- sizes[size]++;
- };
- SCUDO_ALLOCATOR.disable();
- SCUDO_ALLOCATOR.iterateOverChunks(0, -1ul, callback, sizes);
- SCUDO_ALLOCATOR.enable();
- fputs("<malloc version=\"scudo-1\">\n", stream);
- for (scudo::uptr i = 0; i != max_size; ++i)
- if (sizes[i])
- fprintf(stream, "<alloc size=\"%zu\" count=\"%zu\"/>\n", i, sizes[i]);
- fputs("</malloc>\n", stream);
- SCUDO_PREFIX(free)(sizes);
- return 0;
- }
- // Disable memory tagging for the heap. The caller must disable memory tag
- // checks globally (e.g. by clearing TCF0 on aarch64) before calling this
- // function, and may not re-enable them after calling the function.
- INTERFACE WEAK void SCUDO_PREFIX(malloc_disable_memory_tagging)() {
- SCUDO_ALLOCATOR.disableMemoryTagging();
- }
- // Sets whether scudo records stack traces and other metadata for allocations
- // and deallocations. This function only has an effect if the allocator and
- // hardware support memory tagging.
- INTERFACE WEAK void
- SCUDO_PREFIX(malloc_set_track_allocation_stacks)(int track) {
- SCUDO_ALLOCATOR.setTrackAllocationStacks(track);
- }
- // Sets whether scudo zero-initializes all allocated memory.
- INTERFACE WEAK void SCUDO_PREFIX(malloc_set_zero_contents)(int zero_contents) {
- SCUDO_ALLOCATOR.setFillContents(zero_contents ? scudo::ZeroFill
- : scudo::NoFill);
- }
- // Sets whether scudo pattern-initializes all allocated memory.
- INTERFACE WEAK void
- SCUDO_PREFIX(malloc_set_pattern_fill_contents)(int pattern_fill_contents) {
- SCUDO_ALLOCATOR.setFillContents(
- pattern_fill_contents ? scudo::PatternOrZeroFill : scudo::NoFill);
- }
- // Sets whether scudo adds a small amount of slack at the end of large
- // allocations, before the guard page. This can be enabled to work around buggy
- // applications that read a few bytes past the end of their allocation.
- INTERFACE WEAK void
- SCUDO_PREFIX(malloc_set_add_large_allocation_slack)(int add_slack) {
- SCUDO_ALLOCATOR.setAddLargeAllocationSlack(add_slack);
- }
- } // extern "C"
|