xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/wrappers_c.inc (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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