asan_malloc_mac.cc revision 79fc3c042bbe8348fb6f3bff7a5575e4425e5a38
19682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//===-- asan_malloc_mac.cc ------------------------------------------------===//
29682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
39682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//                     The LLVM Compiler Infrastructure
49682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
59682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// This file is distributed under the University of Illinois Open Source
69682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// License. See LICENSE.TXT for details.
79682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
89682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//===----------------------------------------------------------------------===//
99682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// This file is a part of AddressSanitizer, an address sanity checker.
119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Mac-specific malloc interception.
139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//===----------------------------------------------------------------------===//
149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef __APPLE__
169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <AvailabilityMacros.h>
189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <CoreFoundation/CFBase.h>
199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <dlfcn.h>
209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <malloc/malloc.h>
219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asan_allocator.h"
239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asan_interceptors.h"
249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asan_internal.h"
259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asan_mac.h"
269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asan_report.h"
279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asan_stack.h"
289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Similar code is used in Google Perftools,
309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// http://code.google.com/p/google-perftools.
319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// ---------------------- Replacement functions ---------------- {{{1
339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallusing namespace __asan;  // NOLINT
349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// TODO(glider): do we need both zones?
369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic malloc_zone_t *system_malloc_zone = 0;
379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic malloc_zone_t *system_purgeable_zone = 0;
389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic malloc_zone_t asan_zone;
399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallCFAllocatorRef cf_asan = 0;
409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// The free() implementation provided by OS X calls malloc_zone_from_ptr()
429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// to find the owner of |ptr|. If the result is 0, an invalid free() is
439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// reported. Our implementation falls back to asan_free() in this case
449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// in order to print an ASan-style report.
459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// For the objects created by _CFRuntimeCreateInstance a CFAllocatorRef is
479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// placed at the beginning of the allocated chunk and the pointer returned by
489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// our allocator is off by sizeof(CFAllocatorRef). This pointer can be then
499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// passed directly to free(), which will lead to errors.
509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// To overcome this we're checking whether |ptr-sizeof(CFAllocatorRef)|
519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// contains a pointer to our CFAllocator (assuming no other allocator is used).
529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// See http://code.google.com/p/address-sanitizer/issues/detail?id=70 for more
539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// info.
549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallINTERCEPTOR(void, free, void *ptr) {
559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  malloc_zone_t *zone = malloc_zone_from_ptr(ptr);
569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (zone) {
579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(MAC_OS_X_VERSION_10_6) && \
589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if ((zone->version >= 6) && (zone->free_definite_size)) {
609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      zone->free_definite_size(zone, ptr, malloc_size(ptr));
619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    } else {
629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      malloc_zone_free(zone, ptr);
639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#else
659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    malloc_zone_free(zone, ptr);
669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  } else {
689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (flags()->replace_cfallocator) {
699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      // Make sure we're not hitting the previous page. This may be incorrect
709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      // if ASan's malloc returns an address ending with 0xFF8, which will be
719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      // then padded to a page boundary with a CFAllocatorRef.
729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      uptr arith_ptr = (uptr)ptr;
739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      if ((arith_ptr & 0xFFF) > sizeof(CFAllocatorRef)) {
749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        CFAllocatorRef *saved =
759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            (CFAllocatorRef*)(arith_ptr - sizeof(CFAllocatorRef));
769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        if ((*saved == cf_asan) && asan_mz_size(saved)) ptr = (void*)saved;
779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      }
789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    asan_free(ptr, &stack);
819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallnamespace __asan {
859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  void ReplaceCFAllocator();
869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// We can't always replace the default CFAllocator with cf_asan right in
899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// ReplaceSystemMalloc(), because it is sometimes called before
909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// __CFInitialize(), when the default allocator is invalid and replacing it may
919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// crash the program. Instead we wait for the allocator to initialize and jump
929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// in just after __CFInitialize(). Nobody is going to allocate memory using
939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// CFAllocators before that, so we won't miss anything.
949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//
959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// See http://code.google.com/p/address-sanitizer/issues/detail?id=87
969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// and http://opensource.apple.com/source/CF/CF-550.43/CFRuntime.c
979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallINTERCEPTOR(void, __CFInitialize) {
989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  CHECK(flags()->replace_cfallocator);
999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  CHECK(asan_inited);
1009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  REAL(__CFInitialize)();
1019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!cf_asan) ReplaceCFAllocator();
1029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallnamespace {
1059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// TODO(glider): the mz_* functions should be united with the Linux wrappers,
1079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// as they are basically copied from there.
1089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t mz_size(malloc_zone_t* zone, const void* ptr) {
1099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return asan_mz_size(ptr);
1109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid *mz_malloc(malloc_zone_t *zone, size_t size) {
1139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!asan_inited) {
1149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    CHECK(system_malloc_zone);
1159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return malloc_zone_malloc(system_malloc_zone, size);
1169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
1179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  GET_STACK_TRACE_HERE_FOR_MALLOC;
1189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return asan_malloc(size, &stack);
1199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) {
1229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!asan_inited) {
1239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    CHECK(system_malloc_zone);
1249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return malloc_zone_malloc(system_malloc_zone, size);
1259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
1269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  GET_STACK_TRACE_HERE_FOR_MALLOC;
1279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return asan_malloc(size, &stack);
1289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
131  if (!asan_inited) {
132    // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
133    const size_t kCallocPoolSize = 1024;
134    static uptr calloc_memory_for_dlsym[kCallocPoolSize];
135    static size_t allocated;
136    size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
137    void *mem = (void*)&calloc_memory_for_dlsym[allocated];
138    allocated += size_in_words;
139    CHECK(allocated < kCallocPoolSize);
140    return mem;
141  }
142  GET_STACK_TRACE_HERE_FOR_MALLOC;
143  return asan_calloc(nmemb, size, &stack);
144}
145
146void *mz_valloc(malloc_zone_t *zone, size_t size) {
147  if (!asan_inited) {
148    CHECK(system_malloc_zone);
149    return malloc_zone_valloc(system_malloc_zone, size);
150  }
151  GET_STACK_TRACE_HERE_FOR_MALLOC;
152  return asan_memalign(kPageSize, size, &stack);
153}
154
155#define GET_ZONE_FOR_PTR(ptr) \
156  malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
157  const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
158
159void ALWAYS_INLINE free_common(void *context, void *ptr) {
160  if (!ptr) return;
161  if (!flags()->mac_ignore_invalid_free || asan_mz_size(ptr)) {
162    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
163    malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr);
164    if (zone_ptr == system_purgeable_zone) {
165      // Allocations from malloc_default_purgeable_zone() done before
166      // __asan_init() may be occasionally freed via free_common().
167      // See http://code.google.com/p/address-sanitizer/issues/detail?id=99.
168      malloc_zone_free(zone_ptr, ptr);
169    } else {
170      asan_free(ptr, &stack);
171    }
172  } else {
173    // Let us just leak this memory for now.
174    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
175    GET_ZONE_FOR_PTR(ptr);
176    WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
177    return;
178  }
179}
180
181// TODO(glider): the allocation callbacks need to be refactored.
182void mz_free(malloc_zone_t *zone, void *ptr) {
183  free_common(zone, ptr);
184}
185
186void cf_free(void *ptr, void *info) {
187  free_common(info, ptr);
188}
189
190void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
191  if (!ptr) {
192    GET_STACK_TRACE_HERE_FOR_MALLOC;
193    return asan_malloc(size, &stack);
194  } else {
195    if (asan_mz_size(ptr)) {
196      GET_STACK_TRACE_HERE_FOR_MALLOC;
197      return asan_realloc(ptr, size, &stack);
198    } else {
199      // We can't recover from reallocating an unknown address, because
200      // this would require reading at most |size| bytes from
201      // potentially unaccessible memory.
202      GET_STACK_TRACE_HERE_FOR_FREE(ptr);
203      GET_ZONE_FOR_PTR(ptr);
204      ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
205    }
206  }
207}
208
209void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
210  if (!ptr) {
211    GET_STACK_TRACE_HERE_FOR_MALLOC;
212    return asan_malloc(size, &stack);
213  } else {
214    if (asan_mz_size(ptr)) {
215      GET_STACK_TRACE_HERE_FOR_MALLOC;
216      return asan_realloc(ptr, size, &stack);
217    } else {
218      // We can't recover from reallocating an unknown address, because
219      // this would require reading at most |size| bytes from
220      // potentially unaccessible memory.
221      GET_STACK_TRACE_HERE_FOR_FREE(ptr);
222      GET_ZONE_FOR_PTR(ptr);
223      ReportMacCfReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
224    }
225  }
226}
227
228void mz_destroy(malloc_zone_t* zone) {
229  // A no-op -- we will not be destroyed!
230  AsanPrintf("mz_destroy() called -- ignoring\n");
231}
232  // from AvailabilityMacros.h
233#if defined(MAC_OS_X_VERSION_10_6) && \
234    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
235void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
236  if (!asan_inited) {
237    CHECK(system_malloc_zone);
238    return malloc_zone_memalign(system_malloc_zone, align, size);
239  }
240  GET_STACK_TRACE_HERE_FOR_MALLOC;
241  return asan_memalign(align, size, &stack);
242}
243
244// This function is currently unused, and we build with -Werror.
245#if 0
246void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
247  // TODO(glider): check that |size| is valid.
248  UNIMPLEMENTED();
249}
250#endif
251#endif
252
253// malloc_introspection callbacks.  I'm not clear on what all of these do.
254kern_return_t mi_enumerator(task_t task, void *,
255                            unsigned type_mask, vm_address_t zone_address,
256                            memory_reader_t reader,
257                            vm_range_recorder_t recorder) {
258  // Should enumerate all the pointers we have.  Seems like a lot of work.
259  return KERN_FAILURE;
260}
261
262size_t mi_good_size(malloc_zone_t *zone, size_t size) {
263  // I think it's always safe to return size, but we maybe could do better.
264  return size;
265}
266
267boolean_t mi_check(malloc_zone_t *zone) {
268  UNIMPLEMENTED();
269  return true;
270}
271
272void mi_print(malloc_zone_t *zone, boolean_t verbose) {
273  UNIMPLEMENTED();
274  return;
275}
276
277void mi_log(malloc_zone_t *zone, void *address) {
278  // I don't think we support anything like this
279}
280
281void mi_force_lock(malloc_zone_t *zone) {
282  asan_mz_force_lock();
283}
284
285void mi_force_unlock(malloc_zone_t *zone) {
286  asan_mz_force_unlock();
287}
288
289// This function is currently unused, and we build with -Werror.
290#if 0
291void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
292  // TODO(csilvers): figure out how to fill these out
293  // TODO(glider): port this from tcmalloc when ready.
294  stats->blocks_in_use = 0;
295  stats->size_in_use = 0;
296  stats->max_size_in_use = 0;
297  stats->size_allocated = 0;
298}
299#endif
300
301#if defined(MAC_OS_X_VERSION_10_6) && \
302    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
303boolean_t mi_zone_locked(malloc_zone_t *zone) {
304  // UNIMPLEMENTED();
305  return false;
306}
307#endif
308
309}  // unnamed namespace
310
311extern int __CFRuntimeClassTableSize;
312
313namespace __asan {
314void ReplaceCFAllocator() {
315  static CFAllocatorContext asan_context = {
316        /*version*/ 0, /*info*/ &asan_zone,
317        /*retain*/ 0, /*release*/ 0,
318        /*copyDescription*/0,
319        /*allocate*/ &cf_malloc,
320        /*reallocate*/ &cf_realloc,
321        /*deallocate*/ &cf_free,
322        /*preferredSize*/ 0 };
323  if (!cf_asan)
324    cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
325  if (CFAllocatorGetDefault() != cf_asan)
326    CFAllocatorSetDefault(cf_asan);
327}
328
329void ReplaceSystemMalloc() {
330  static malloc_introspection_t asan_introspection;
331  // Ok to use internal_memset, these places are not performance-critical.
332  internal_memset(&asan_introspection, 0, sizeof(asan_introspection));
333
334  asan_introspection.enumerator = &mi_enumerator;
335  asan_introspection.good_size = &mi_good_size;
336  asan_introspection.check = &mi_check;
337  asan_introspection.print = &mi_print;
338  asan_introspection.log = &mi_log;
339  asan_introspection.force_lock = &mi_force_lock;
340  asan_introspection.force_unlock = &mi_force_unlock;
341
342  internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));
343
344  // Start with a version 4 zone which is used for OS X 10.4 and 10.5.
345  asan_zone.version = 4;
346  asan_zone.zone_name = "asan";
347  asan_zone.size = &mz_size;
348  asan_zone.malloc = &mz_malloc;
349  asan_zone.calloc = &mz_calloc;
350  asan_zone.valloc = &mz_valloc;
351  asan_zone.free = &mz_free;
352  asan_zone.realloc = &mz_realloc;
353  asan_zone.destroy = &mz_destroy;
354  asan_zone.batch_malloc = 0;
355  asan_zone.batch_free = 0;
356  asan_zone.introspect = &asan_introspection;
357
358  // from AvailabilityMacros.h
359#if defined(MAC_OS_X_VERSION_10_6) && \
360    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
361  // Switch to version 6 on OSX 10.6 to support memalign.
362  asan_zone.version = 6;
363  asan_zone.free_definite_size = 0;
364  asan_zone.memalign = &mz_memalign;
365  asan_introspection.zone_locked = &mi_zone_locked;
366
367  // Request the default purgable zone to force its creation. The
368  // current default zone is registered with the purgable zone for
369  // doing tiny and small allocs.  Sadly, it assumes that the default
370  // zone is the szone implementation from OS X and will crash if it
371  // isn't.  By creating the zone now, this will be true and changing
372  // the default zone won't cause a problem.  (OS X 10.6 and higher.)
373  system_purgeable_zone = malloc_default_purgeable_zone();
374#endif
375
376  // Register the ASan zone. At this point, it will not be the
377  // default zone.
378  malloc_zone_register(&asan_zone);
379
380  // Unregister and reregister the default zone.  Unregistering swaps
381  // the specified zone with the last one registered which for the
382  // default zone makes the more recently registered zone the default
383  // zone.  The default zone is then re-registered to ensure that
384  // allocations made from it earlier will be handled correctly.
385  // Things are not guaranteed to work that way, but it's how they work now.
386  system_malloc_zone = malloc_default_zone();
387  malloc_zone_unregister(system_malloc_zone);
388  malloc_zone_register(system_malloc_zone);
389  // Make sure the default allocator was replaced.
390  CHECK(malloc_default_zone() == &asan_zone);
391
392  if (flags()->replace_cfallocator) {
393    // If __CFInitialize() hasn't been called yet, cf_asan will be created and
394    // installed as the default allocator after __CFInitialize() finishes (see
395    // the interceptor for __CFInitialize() above). Otherwise install cf_asan
396    // right now. On both Snow Leopard and Lion __CFInitialize() calls
397    // __CFAllocatorInitialize(), which initializes the _base._cfisa field of
398    // the default allocators we check here.
399    if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
400      ReplaceCFAllocator();
401    }
402  }
403}
404}  // namespace __asan
405
406#endif  // __APPLE__
407