10b57cec5SDimitry Andric//===-- sanitizer_malloc_mac.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// This file contains Mac-specific malloc interceptors and a custom zone
100b57cec5SDimitry Andric// implementation, which together replace the system allocator.
110b57cec5SDimitry Andric//
120b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric#include "sanitizer_common/sanitizer_platform.h"
150b57cec5SDimitry Andric#if !SANITIZER_MAC
160b57cec5SDimitry Andric#error "This file should only be compiled on Darwin."
170b57cec5SDimitry Andric#endif
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric#include <AvailabilityMacros.h>
200b57cec5SDimitry Andric#include <CoreFoundation/CFBase.h>
210b57cec5SDimitry Andric#include <dlfcn.h>
220b57cec5SDimitry Andric#include <malloc/malloc.h>
230b57cec5SDimitry Andric#include <sys/mman.h>
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric#include "interception/interception.h"
260b57cec5SDimitry Andric#include "sanitizer_common/sanitizer_mac.h"
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric// Similar code is used in Google Perftools,
290b57cec5SDimitry Andric// https://github.com/gperftools/gperftools.
300b57cec5SDimitry Andric
310b57cec5SDimitry Andricnamespace __sanitizer {
320b57cec5SDimitry Andric
330b57cec5SDimitry Andricextern malloc_zone_t sanitizer_zone;
340b57cec5SDimitry Andric
350b57cec5SDimitry Andricstruct sanitizer_malloc_introspection_t : public malloc_introspection_t {
360b57cec5SDimitry Andric  // IMPORTANT: Do not change the order, alignment, or types of these fields to
370b57cec5SDimitry Andric  // maintain binary compatibility. You should only add fields to this struct.
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric  // Used to track changes to the allocator that will affect
400b57cec5SDimitry Andric  // zone enumeration.
410b57cec5SDimitry Andric  u64 allocator_enumeration_version;
420b57cec5SDimitry Andric  uptr allocator_ptr;
430b57cec5SDimitry Andric  uptr allocator_size;
440b57cec5SDimitry Andric};
450b57cec5SDimitry Andric
460b57cec5SDimitry Andricu64 GetMallocZoneAllocatorEnumerationVersion() {
470b57cec5SDimitry Andric  // This represents the current allocator ABI version.
480b57cec5SDimitry Andric  // This field should be incremented every time the Allocator
490b57cec5SDimitry Andric  // ABI changes in a way that breaks allocator enumeration.
500b57cec5SDimitry Andric  return 0;
510b57cec5SDimitry Andric}
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric}  // namespace __sanitizer
540b57cec5SDimitry Andric
550b57cec5SDimitry AndricINTERCEPTOR(malloc_zone_t *, malloc_create_zone,
560b57cec5SDimitry Andric                             vm_size_t start_size, unsigned zone_flags) {
570b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
580b57cec5SDimitry Andric  uptr page_size = GetPageSizeCached();
590b57cec5SDimitry Andric  uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
600b57cec5SDimitry Andric  COMMON_MALLOC_MEMALIGN(page_size, allocated_size);
610b57cec5SDimitry Andric  malloc_zone_t *new_zone = (malloc_zone_t *)p;
620b57cec5SDimitry Andric  internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
630b57cec5SDimitry Andric  new_zone->zone_name = NULL;  // The name will be changed anyway.
640b57cec5SDimitry Andric  if (GetMacosVersion() >= MACOS_VERSION_LION) {
650b57cec5SDimitry Andric    // Prevent the client app from overwriting the zone contents.
660b57cec5SDimitry Andric    // Library functions that need to modify the zone will set PROT_WRITE on it.
670b57cec5SDimitry Andric    // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
680b57cec5SDimitry Andric    mprotect(new_zone, allocated_size, PROT_READ);
690b57cec5SDimitry Andric  }
700b57cec5SDimitry Andric  // We're explicitly *NOT* registering the zone.
710b57cec5SDimitry Andric  return new_zone;
720b57cec5SDimitry Andric}
730b57cec5SDimitry Andric
740b57cec5SDimitry AndricINTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) {
750b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
760b57cec5SDimitry Andric  // We don't need to do anything here.  We're not registering new zones, so we
770b57cec5SDimitry Andric  // don't to unregister.  Just un-mprotect and free() the zone.
780b57cec5SDimitry Andric  if (GetMacosVersion() >= MACOS_VERSION_LION) {
790b57cec5SDimitry Andric    uptr page_size = GetPageSizeCached();
800b57cec5SDimitry Andric    uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
810b57cec5SDimitry Andric    mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
820b57cec5SDimitry Andric  }
830b57cec5SDimitry Andric  if (zone->zone_name) {
840b57cec5SDimitry Andric    COMMON_MALLOC_FREE((void *)zone->zone_name);
850b57cec5SDimitry Andric  }
860b57cec5SDimitry Andric  COMMON_MALLOC_FREE(zone);
870b57cec5SDimitry Andric}
880b57cec5SDimitry Andric
890b57cec5SDimitry AndricINTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
900b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
910b57cec5SDimitry Andric  return &sanitizer_zone;
920b57cec5SDimitry Andric}
930b57cec5SDimitry Andric
940b57cec5SDimitry AndricINTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
950b57cec5SDimitry Andric  // FIXME: ASan should support purgeable allocations.
960b57cec5SDimitry Andric  // https://github.com/google/sanitizers/issues/139
970b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
980b57cec5SDimitry Andric  return &sanitizer_zone;
990b57cec5SDimitry Andric}
1000b57cec5SDimitry Andric
1010b57cec5SDimitry AndricINTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
1020b57cec5SDimitry Andric  // FIXME: ASan should support purgeable allocations. Ignoring them is fine
1030b57cec5SDimitry Andric  // for now.
1040b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1050b57cec5SDimitry Andric}
1060b57cec5SDimitry Andric
1070b57cec5SDimitry AndricINTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
1080b57cec5SDimitry Andric  // FIXME: ASan should support purgeable allocations. Ignoring them is fine
1090b57cec5SDimitry Andric  // for now.
1100b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1110b57cec5SDimitry Andric  // Must return 0 if the contents were not purged since the last call to
1120b57cec5SDimitry Andric  // malloc_make_purgeable().
1130b57cec5SDimitry Andric  return 0;
1140b57cec5SDimitry Andric}
1150b57cec5SDimitry Andric
1160b57cec5SDimitry AndricINTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
1170b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1180b57cec5SDimitry Andric  // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
1190b57cec5SDimitry Andric  // bytes.
1200b57cec5SDimitry Andric  size_t buflen =
1210b57cec5SDimitry Andric      sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
1220b57cec5SDimitry Andric  InternalScopedString new_name(buflen);
1230b57cec5SDimitry Andric  if (name && zone->introspect == sanitizer_zone.introspect) {
1240b57cec5SDimitry Andric    new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
1250b57cec5SDimitry Andric    name = new_name.data();
1260b57cec5SDimitry Andric  }
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric  // Call the system malloc's implementation for both external and our zones,
1290b57cec5SDimitry Andric  // since that appropriately changes VM region protections on the zone.
1300b57cec5SDimitry Andric  REAL(malloc_set_zone_name)(zone, name);
1310b57cec5SDimitry Andric}
1320b57cec5SDimitry Andric
1330b57cec5SDimitry AndricINTERCEPTOR(void *, malloc, size_t size) {
1340b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1350b57cec5SDimitry Andric  COMMON_MALLOC_MALLOC(size);
1360b57cec5SDimitry Andric  return p;
1370b57cec5SDimitry Andric}
1380b57cec5SDimitry Andric
1390b57cec5SDimitry AndricINTERCEPTOR(void, free, void *ptr) {
1400b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1410b57cec5SDimitry Andric  if (!ptr) return;
1420b57cec5SDimitry Andric  COMMON_MALLOC_FREE(ptr);
1430b57cec5SDimitry Andric}
1440b57cec5SDimitry Andric
1450b57cec5SDimitry AndricINTERCEPTOR(void *, realloc, void *ptr, size_t size) {
1460b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1470b57cec5SDimitry Andric  COMMON_MALLOC_REALLOC(ptr, size);
1480b57cec5SDimitry Andric  return p;
1490b57cec5SDimitry Andric}
1500b57cec5SDimitry Andric
1510b57cec5SDimitry AndricINTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
1520b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1530b57cec5SDimitry Andric  COMMON_MALLOC_CALLOC(nmemb, size);
1540b57cec5SDimitry Andric  return p;
1550b57cec5SDimitry Andric}
1560b57cec5SDimitry Andric
1570b57cec5SDimitry AndricINTERCEPTOR(void *, valloc, size_t size) {
1580b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1590b57cec5SDimitry Andric  COMMON_MALLOC_VALLOC(size);
1600b57cec5SDimitry Andric  return p;
1610b57cec5SDimitry Andric}
1620b57cec5SDimitry Andric
1630b57cec5SDimitry AndricINTERCEPTOR(size_t, malloc_good_size, size_t size) {
1640b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1650b57cec5SDimitry Andric  return sanitizer_zone.introspect->good_size(&sanitizer_zone, size);
1660b57cec5SDimitry Andric}
1670b57cec5SDimitry Andric
1680b57cec5SDimitry AndricINTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
1690b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1700b57cec5SDimitry Andric  CHECK(memptr);
1710b57cec5SDimitry Andric  COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size);
1720b57cec5SDimitry Andric  return res;
1730b57cec5SDimitry Andric}
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andricnamespace {
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric// TODO(glider): the __sanitizer_mz_* functions should be united with the Linux
1780b57cec5SDimitry Andric// wrappers, as they are basically copied from there.
1790b57cec5SDimitry Andricextern "C"
1800b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
1810b57cec5SDimitry Andricsize_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) {
1820b57cec5SDimitry Andric  COMMON_MALLOC_SIZE(ptr);
1830b57cec5SDimitry Andric  return size;
1840b57cec5SDimitry Andric}
1850b57cec5SDimitry Andric
1860b57cec5SDimitry Andricextern "C"
1870b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
1880b57cec5SDimitry Andricvoid *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) {
1890b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
1900b57cec5SDimitry Andric  COMMON_MALLOC_MALLOC(size);
1910b57cec5SDimitry Andric  return p;
1920b57cec5SDimitry Andric}
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andricextern "C"
1950b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
1960b57cec5SDimitry Andricvoid *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
1970b57cec5SDimitry Andric  if (UNLIKELY(!COMMON_MALLOC_SANITIZER_INITIALIZED)) {
1980b57cec5SDimitry Andric    // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
1990b57cec5SDimitry Andric    const size_t kCallocPoolSize = 1024;
2000b57cec5SDimitry Andric    static uptr calloc_memory_for_dlsym[kCallocPoolSize];
2010b57cec5SDimitry Andric    static size_t allocated;
2020b57cec5SDimitry Andric    size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
2030b57cec5SDimitry Andric    void *mem = (void*)&calloc_memory_for_dlsym[allocated];
2040b57cec5SDimitry Andric    allocated += size_in_words;
2050b57cec5SDimitry Andric    CHECK(allocated < kCallocPoolSize);
2060b57cec5SDimitry Andric    return mem;
2070b57cec5SDimitry Andric  }
2080b57cec5SDimitry Andric  COMMON_MALLOC_CALLOC(nmemb, size);
2090b57cec5SDimitry Andric  return p;
2100b57cec5SDimitry Andric}
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andricextern "C"
2130b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
2140b57cec5SDimitry Andricvoid *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) {
2150b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
2160b57cec5SDimitry Andric  COMMON_MALLOC_VALLOC(size);
2170b57cec5SDimitry Andric  return p;
2180b57cec5SDimitry Andric}
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andric// TODO(glider): the allocation callbacks need to be refactored.
2210b57cec5SDimitry Andricextern "C"
2220b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
2230b57cec5SDimitry Andricvoid __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) {
2240b57cec5SDimitry Andric  if (!ptr) return;
2250b57cec5SDimitry Andric  COMMON_MALLOC_FREE(ptr);
2260b57cec5SDimitry Andric}
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric#define GET_ZONE_FOR_PTR(ptr) \
2290b57cec5SDimitry Andric  malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
2300b57cec5SDimitry Andric  const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andricextern "C"
2330b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
2340b57cec5SDimitry Andricvoid *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) {
2350b57cec5SDimitry Andric  if (!ptr) {
2360b57cec5SDimitry Andric    COMMON_MALLOC_MALLOC(new_size);
2370b57cec5SDimitry Andric    return p;
2380b57cec5SDimitry Andric  } else {
2390b57cec5SDimitry Andric    COMMON_MALLOC_SIZE(ptr);
2400b57cec5SDimitry Andric    if (size) {
2410b57cec5SDimitry Andric      COMMON_MALLOC_REALLOC(ptr, new_size);
2420b57cec5SDimitry Andric      return p;
2430b57cec5SDimitry Andric    } else {
2440b57cec5SDimitry Andric      // We can't recover from reallocating an unknown address, because
2450b57cec5SDimitry Andric      // this would require reading at most |new_size| bytes from
2460b57cec5SDimitry Andric      // potentially unaccessible memory.
2470b57cec5SDimitry Andric      GET_ZONE_FOR_PTR(ptr);
2480b57cec5SDimitry Andric      COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name);
2490b57cec5SDimitry Andric      return nullptr;
2500b57cec5SDimitry Andric    }
2510b57cec5SDimitry Andric  }
2520b57cec5SDimitry Andric}
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andricextern "C"
2550b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
2560b57cec5SDimitry Andricvoid __sanitizer_mz_destroy(malloc_zone_t* zone) {
2570b57cec5SDimitry Andric  // A no-op -- we will not be destroyed!
2580b57cec5SDimitry Andric  Report("__sanitizer_mz_destroy() called -- ignoring\n");
2590b57cec5SDimitry Andric}
2600b57cec5SDimitry Andric
2610b57cec5SDimitry Andricextern "C"
2620b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
2630b57cec5SDimitry Andricvoid *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
2640b57cec5SDimitry Andric  COMMON_MALLOC_ENTER();
2650b57cec5SDimitry Andric  COMMON_MALLOC_MEMALIGN(align, size);
2660b57cec5SDimitry Andric  return p;
2670b57cec5SDimitry Andric}
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric// This public API exists purely for testing purposes.
2700b57cec5SDimitry Andricextern "C"
2710b57cec5SDimitry AndricSANITIZER_INTERFACE_ATTRIBUTE
2720b57cec5SDimitry Andricmalloc_zone_t* __sanitizer_mz_default_zone() {
2730b57cec5SDimitry Andric  return &sanitizer_zone;
2740b57cec5SDimitry Andric}
2750b57cec5SDimitry Andric
2760b57cec5SDimitry Andric// This function is currently unused, and we build with -Werror.
2770b57cec5SDimitry Andric#if 0
2780b57cec5SDimitry Andricvoid __sanitizer_mz_free_definite_size(
2790b57cec5SDimitry Andric    malloc_zone_t* zone, void *ptr, size_t size) {
2800b57cec5SDimitry Andric  // TODO(glider): check that |size| is valid.
2810b57cec5SDimitry Andric  UNIMPLEMENTED();
2820b57cec5SDimitry Andric}
2830b57cec5SDimitry Andric#endif
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric#ifndef COMMON_MALLOC_HAS_ZONE_ENUMERATOR
2860b57cec5SDimitry Andric#error "COMMON_MALLOC_HAS_ZONE_ENUMERATOR must be defined"
2870b57cec5SDimitry Andric#endif
2880b57cec5SDimitry Andricstatic_assert((COMMON_MALLOC_HAS_ZONE_ENUMERATOR) == 0 ||
2890b57cec5SDimitry Andric                  (COMMON_MALLOC_HAS_ZONE_ENUMERATOR) == 1,
2900b57cec5SDimitry Andric              "COMMON_MALLOC_HAS_ZONE_ENUMERATOR must be 0 or 1");
2910b57cec5SDimitry Andric
2920b57cec5SDimitry Andric#if COMMON_MALLOC_HAS_ZONE_ENUMERATOR
2930b57cec5SDimitry Andric// Forward declare and expect the implementation to provided by
2940b57cec5SDimitry Andric// includer.
2950b57cec5SDimitry Andrickern_return_t mi_enumerator(task_t task, void *, unsigned type_mask,
2960b57cec5SDimitry Andric                            vm_address_t zone_address, memory_reader_t reader,
2970b57cec5SDimitry Andric                            vm_range_recorder_t recorder);
2980b57cec5SDimitry Andric#else
2990b57cec5SDimitry Andric// Provide stub implementation that fails.
3000b57cec5SDimitry Andrickern_return_t mi_enumerator(task_t task, void *, unsigned type_mask,
3010b57cec5SDimitry Andric                            vm_address_t zone_address, memory_reader_t reader,
3020b57cec5SDimitry Andric                            vm_range_recorder_t recorder) {
3030b57cec5SDimitry Andric  // Not supported.
3040b57cec5SDimitry Andric  return KERN_FAILURE;
3050b57cec5SDimitry Andric}
3060b57cec5SDimitry Andric#endif
3070b57cec5SDimitry Andric
3080b57cec5SDimitry Andric#ifndef COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT
3090b57cec5SDimitry Andric#error "COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT must be defined"
3100b57cec5SDimitry Andric#endif
3110b57cec5SDimitry Andricstatic_assert((COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT) == 0 ||
3120b57cec5SDimitry Andric                  (COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT) == 1,
3130b57cec5SDimitry Andric              "COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT must be 0 or 1");
3140b57cec5SDimitry Andric#if COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT
3150b57cec5SDimitry Andric// Forward declare and expect the implementation to provided by
3160b57cec5SDimitry Andric// includer.
3170b57cec5SDimitry Andricvoid mi_extra_init(
3180b57cec5SDimitry Andric    sanitizer_malloc_introspection_t *mi);
3190b57cec5SDimitry Andric#else
3200b57cec5SDimitry Andricvoid mi_extra_init(
3210b57cec5SDimitry Andric    sanitizer_malloc_introspection_t *mi) {
3220b57cec5SDimitry Andric  // Just zero initialize the fields.
3230b57cec5SDimitry Andric  mi->allocator_ptr = 0;
3240b57cec5SDimitry Andric  mi->allocator_size = 0;
3250b57cec5SDimitry Andric}
3260b57cec5SDimitry Andric#endif
3270b57cec5SDimitry Andric
3280b57cec5SDimitry Andricsize_t mi_good_size(malloc_zone_t *zone, size_t size) {
3290b57cec5SDimitry Andric  // I think it's always safe to return size, but we maybe could do better.
3300b57cec5SDimitry Andric  return size;
3310b57cec5SDimitry Andric}
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andricboolean_t mi_check(malloc_zone_t *zone) {
3340b57cec5SDimitry Andric  UNIMPLEMENTED();
3350b57cec5SDimitry Andric}
3360b57cec5SDimitry Andric
3370b57cec5SDimitry Andricvoid mi_print(malloc_zone_t *zone, boolean_t verbose) {
3380b57cec5SDimitry Andric  UNIMPLEMENTED();
3390b57cec5SDimitry Andric}
3400b57cec5SDimitry Andric
3410b57cec5SDimitry Andricvoid mi_log(malloc_zone_t *zone, void *address) {
3420b57cec5SDimitry Andric  // I don't think we support anything like this
3430b57cec5SDimitry Andric}
3440b57cec5SDimitry Andric
3450b57cec5SDimitry Andricvoid mi_force_lock(malloc_zone_t *zone) {
3460b57cec5SDimitry Andric  COMMON_MALLOC_FORCE_LOCK();
3470b57cec5SDimitry Andric}
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andricvoid mi_force_unlock(malloc_zone_t *zone) {
3500b57cec5SDimitry Andric  COMMON_MALLOC_FORCE_UNLOCK();
3510b57cec5SDimitry Andric}
3520b57cec5SDimitry Andric
3530b57cec5SDimitry Andricvoid mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
3540b57cec5SDimitry Andric  COMMON_MALLOC_FILL_STATS(zone, stats);
3550b57cec5SDimitry Andric}
3560b57cec5SDimitry Andric
3570b57cec5SDimitry Andricboolean_t mi_zone_locked(malloc_zone_t *zone) {
3580b57cec5SDimitry Andric  // UNIMPLEMENTED();
3590b57cec5SDimitry Andric  return false;
3600b57cec5SDimitry Andric}
3610b57cec5SDimitry Andric
3620b57cec5SDimitry Andric}  // unnamed namespace
3630b57cec5SDimitry Andric
3640b57cec5SDimitry Andricnamespace COMMON_MALLOC_NAMESPACE {
3650b57cec5SDimitry Andric
3660b57cec5SDimitry Andricvoid InitMallocZoneFields() {
3670b57cec5SDimitry Andric  static sanitizer_malloc_introspection_t sanitizer_zone_introspection;
3680b57cec5SDimitry Andric  // Ok to use internal_memset, these places are not performance-critical.
3690b57cec5SDimitry Andric  internal_memset(&sanitizer_zone_introspection, 0,
3700b57cec5SDimitry Andric                  sizeof(sanitizer_zone_introspection));
3710b57cec5SDimitry Andric
3720b57cec5SDimitry Andric  sanitizer_zone_introspection.enumerator = &mi_enumerator;
3730b57cec5SDimitry Andric  sanitizer_zone_introspection.good_size = &mi_good_size;
3740b57cec5SDimitry Andric  sanitizer_zone_introspection.check = &mi_check;
3750b57cec5SDimitry Andric  sanitizer_zone_introspection.print = &mi_print;
3760b57cec5SDimitry Andric  sanitizer_zone_introspection.log = &mi_log;
3770b57cec5SDimitry Andric  sanitizer_zone_introspection.force_lock = &mi_force_lock;
3780b57cec5SDimitry Andric  sanitizer_zone_introspection.force_unlock = &mi_force_unlock;
3790b57cec5SDimitry Andric  sanitizer_zone_introspection.statistics = &mi_statistics;
3800b57cec5SDimitry Andric  sanitizer_zone_introspection.zone_locked = &mi_zone_locked;
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric  // Set current allocator enumeration version.
3830b57cec5SDimitry Andric  sanitizer_zone_introspection.allocator_enumeration_version =
3840b57cec5SDimitry Andric      GetMallocZoneAllocatorEnumerationVersion();
3850b57cec5SDimitry Andric
3860b57cec5SDimitry Andric  // Perform any sanitizer specific initialization.
3870b57cec5SDimitry Andric  mi_extra_init(&sanitizer_zone_introspection);
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric  internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t));
3900b57cec5SDimitry Andric
3910b57cec5SDimitry Andric  // Use version 6 for OSX >= 10.6.
3920b57cec5SDimitry Andric  sanitizer_zone.version = 6;
3930b57cec5SDimitry Andric  sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME;
3940b57cec5SDimitry Andric  sanitizer_zone.size = &__sanitizer_mz_size;
3950b57cec5SDimitry Andric  sanitizer_zone.malloc = &__sanitizer_mz_malloc;
3960b57cec5SDimitry Andric  sanitizer_zone.calloc = &__sanitizer_mz_calloc;
3970b57cec5SDimitry Andric  sanitizer_zone.valloc = &__sanitizer_mz_valloc;
3980b57cec5SDimitry Andric  sanitizer_zone.free = &__sanitizer_mz_free;
3990b57cec5SDimitry Andric  sanitizer_zone.realloc = &__sanitizer_mz_realloc;
4000b57cec5SDimitry Andric  sanitizer_zone.destroy = &__sanitizer_mz_destroy;
4010b57cec5SDimitry Andric  sanitizer_zone.batch_malloc = 0;
4020b57cec5SDimitry Andric  sanitizer_zone.batch_free = 0;
4030b57cec5SDimitry Andric  sanitizer_zone.free_definite_size = 0;
4040b57cec5SDimitry Andric  sanitizer_zone.memalign = &__sanitizer_mz_memalign;
4050b57cec5SDimitry Andric  sanitizer_zone.introspect = &sanitizer_zone_introspection;
4060b57cec5SDimitry Andric}
4070b57cec5SDimitry Andric
4080b57cec5SDimitry Andricvoid ReplaceSystemMalloc() {
4090b57cec5SDimitry Andric  InitMallocZoneFields();
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric  // Register the zone.
4120b57cec5SDimitry Andric  malloc_zone_register(&sanitizer_zone);
4130b57cec5SDimitry Andric}
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric}  // namespace COMMON_MALLOC_NAMESPACE
416