aboutsummaryrefslogtreecommitdiff
path: root/lib/asan/asan_malloc_mac.cc
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2013-01-18 20:06:45 +0000
committerAndrew Turner <andrew@FreeBSD.org>2013-01-18 20:06:45 +0000
commit58aabf08b77d221489f10e274812ec60917c21a8 (patch)
treeb946f82269be87d83f086167c762c362e734c5bb /lib/asan/asan_malloc_mac.cc
parent37dfff057418e02f8e5322da12684dd927e3d881 (diff)
downloadsrc-58aabf08b77d221489f10e274812ec60917c21a8.tar.gz
src-58aabf08b77d221489f10e274812ec60917c21a8.zip
Import compiler-rt r172839.vendor/compiler-rt/compiler-rt-r172839
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=245614 svn path=/vendor/compiler-rt/compiler-rt-r172839/; revision=245615; tag=vendor/compiler-rt/compiler-rt-r172839
Diffstat (limited to 'lib/asan/asan_malloc_mac.cc')
-rw-r--r--lib/asan/asan_malloc_mac.cc195
1 files changed, 97 insertions, 98 deletions
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index 1a6c84052a0a..545ede2debe7 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -1,4 +1,4 @@
-//===-- asan_rtl.cc -------------------------------------------------------===//
+//===-- asan_malloc_mac.cc ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -18,13 +18,15 @@
#include <CoreFoundation/CFBase.h>
#include <dlfcn.h>
#include <malloc/malloc.h>
-#include <setjmp.h>
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mac.h"
+#include "asan_report.h"
#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_thread_registry.h"
// Similar code is used in Google Perftools,
// http://code.google.com/p/google-perftools.
@@ -38,6 +40,30 @@ static malloc_zone_t *system_purgeable_zone = 0;
static malloc_zone_t asan_zone;
CFAllocatorRef cf_asan = 0;
+// _CFRuntimeCreateInstance() checks whether the supplied allocator is
+// kCFAllocatorSystemDefault and, if it is not, stores the allocator reference
+// at the beginning of the allocated memory and returns the pointer to the
+// allocated memory plus sizeof(CFAllocatorRef). See
+// http://www.opensource.apple.com/source/CF/CF-635.21/CFRuntime.c
+// Pointers returned by _CFRuntimeCreateInstance() can then be passed directly
+// to free() or CFAllocatorDeallocate(), which leads to false invalid free
+// reports.
+// The corresponding rdar bug is http://openradar.appspot.com/radar?id=1796404.
+void* ALWAYS_INLINE get_saved_cfallocator_ref(void *ptr) {
+ if (flags()->replace_cfallocator) {
+ // Make sure we're not hitting the previous page. This may be incorrect
+ // if ASan's malloc returns an address ending with 0xFF8, which will be
+ // then padded to a page boundary with a CFAllocatorRef.
+ uptr arith_ptr = (uptr)ptr;
+ if ((arith_ptr & 0xFFF) > sizeof(CFAllocatorRef)) {
+ CFAllocatorRef *saved =
+ (CFAllocatorRef*)(arith_ptr - sizeof(CFAllocatorRef));
+ if ((*saved == cf_asan) && asan_mz_size(saved)) ptr = (void*)saved;
+ }
+ }
+ return ptr;
+}
+
// The free() implementation provided by OS X calls malloc_zone_from_ptr()
// to find the owner of |ptr|. If the result is 0, an invalid free() is
// reported. Our implementation falls back to asan_free() in this case
@@ -65,26 +91,12 @@ INTERCEPTOR(void, free, void *ptr) {
malloc_zone_free(zone, ptr);
#endif
} else {
- if (flags()->replace_cfallocator) {
- // Make sure we're not hitting the previous page. This may be incorrect
- // if ASan's malloc returns an address ending with 0xFF8, which will be
- // then padded to a page boundary with a CFAllocatorRef.
- uptr arith_ptr = (uptr)ptr;
- if ((arith_ptr & 0xFFF) > sizeof(CFAllocatorRef)) {
- CFAllocatorRef *saved =
- (CFAllocatorRef*)(arith_ptr - sizeof(CFAllocatorRef));
- if ((*saved == cf_asan) && asan_mz_size(saved)) ptr = (void*)saved;
- }
- }
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
- asan_free(ptr, &stack);
+ if (!asan_mz_size(ptr)) ptr = get_saved_cfallocator_ref(ptr);
+ GET_STACK_TRACE_FREE;
+ asan_free(ptr, &stack, FROM_MALLOC);
}
}
-namespace __asan {
- void ReplaceCFAllocator();
-}
-
// We can't always replace the default CFAllocator with cf_asan right in
// ReplaceSystemMalloc(), because it is sometimes called before
// __CFInitialize(), when the default allocator is invalid and replacing it may
@@ -94,11 +106,15 @@ namespace __asan {
//
// See http://code.google.com/p/address-sanitizer/issues/detail?id=87
// and http://opensource.apple.com/source/CF/CF-550.43/CFRuntime.c
-INTERCEPTOR(void, __CFInitialize) {
+INTERCEPTOR(void, __CFInitialize, void) {
+ // If the runtime is built as dynamic library, __CFInitialize wrapper may be
+ // called before __asan_init.
+#if !MAC_INTERPOSE_FUNCTIONS
CHECK(flags()->replace_cfallocator);
CHECK(asan_inited);
+#endif
REAL(__CFInitialize)();
- if (!cf_asan) ReplaceCFAllocator();
+ if (!cf_asan && asan_inited) MaybeReplaceCFAllocator();
}
namespace {
@@ -114,7 +130,7 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
@@ -123,7 +139,7 @@ void *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
@@ -139,7 +155,7 @@ void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
CHECK(allocated < kCallocPoolSize);
return mem;
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
@@ -148,39 +164,41 @@ void *mz_valloc(malloc_zone_t *zone, size_t size) {
CHECK(system_malloc_zone);
return malloc_zone_valloc(system_malloc_zone, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
- return asan_memalign(kPageSize, size, &stack);
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}
-void print_zone_for_ptr(void *ptr) {
- malloc_zone_t *orig_zone = malloc_zone_from_ptr(ptr);
- if (orig_zone) {
- if (orig_zone->zone_name) {
- AsanPrintf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
- ptr, orig_zone, orig_zone->zone_name);
- } else {
- AsanPrintf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
- ptr, orig_zone);
- }
- } else {
- AsanPrintf("malloc_zone_from_ptr(%p) = 0\n", ptr);
- }
-}
+#define GET_ZONE_FOR_PTR(ptr) \
+ malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
+ const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
void ALWAYS_INLINE free_common(void *context, void *ptr) {
if (!ptr) return;
- if (!flags()->mac_ignore_invalid_free || asan_mz_size(ptr)) {
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
- asan_free(ptr, &stack);
+ if (asan_mz_size(ptr)) {
+ GET_STACK_TRACE_FREE;
+ asan_free(ptr, &stack, FROM_MALLOC);
} else {
- // Let us just leak this memory for now.
- AsanPrintf("free_common(%p) -- attempting to free unallocated memory.\n"
- "AddressSanitizer is ignoring this error on Mac OS now.\n",
- ptr);
- print_zone_for_ptr(ptr);
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
- stack.PrintStack();
- return;
+ // If the pointer does not belong to any of the zones, use one of the
+ // fallback methods to free memory.
+ malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr);
+ if (zone_ptr == system_purgeable_zone) {
+ // allocations from malloc_default_purgeable_zone() done before
+ // __asan_init() may be occasionally freed via free_common().
+ // see http://code.google.com/p/address-sanitizer/issues/detail?id=99.
+ malloc_zone_free(zone_ptr, ptr);
+ } else {
+ // If the memory chunk pointer was moved to store additional
+ // CFAllocatorRef, fix it back.
+ ptr = get_saved_cfallocator_ref(ptr);
+ GET_STACK_TRACE_FREE;
+ if (!flags()->mac_ignore_invalid_free) {
+ asan_free(ptr, &stack, FROM_MALLOC);
+ } else {
+ GET_ZONE_FOR_PTR(ptr);
+ WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
+ return;
+ }
+ }
}
}
@@ -195,55 +213,45 @@ void cf_free(void *ptr, void *info) {
void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
if (!ptr) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
} else {
if (asan_mz_size(ptr)) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
} else {
// We can't recover from reallocating an unknown address, because
// this would require reading at most |size| bytes from
// potentially unaccessible memory.
- AsanPrintf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
- "This is an unrecoverable problem, exiting now.\n",
- ptr);
- print_zone_for_ptr(ptr);
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
- stack.PrintStack();
- ShowStatsAndAbort();
- return 0; // unreachable
+ GET_STACK_TRACE_FREE;
+ GET_ZONE_FOR_PTR(ptr);
+ ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
}
}
}
void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
if (!ptr) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
} else {
if (asan_mz_size(ptr)) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
} else {
// We can't recover from reallocating an unknown address, because
// this would require reading at most |size| bytes from
// potentially unaccessible memory.
- AsanPrintf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
- "This is an unrecoverable problem, exiting now.\n",
- ptr);
- print_zone_for_ptr(ptr);
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
- stack.PrintStack();
- ShowStatsAndAbort();
- return 0; // unreachable
+ GET_STACK_TRACE_FREE;
+ GET_ZONE_FOR_PTR(ptr);
+ ReportMacCfReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
}
}
}
void mz_destroy(malloc_zone_t* zone) {
// A no-op -- we will not be destroyed!
- AsanPrintf("mz_destroy() called -- ignoring\n");
+ Printf("mz_destroy() called -- ignoring\n");
}
// from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
@@ -253,8 +261,8 @@ void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
CHECK(system_malloc_zone);
return malloc_zone_memalign(system_malloc_zone, align, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
- return asan_memalign(align, size, &stack);
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(align, size, &stack, FROM_MALLOC);
}
// This function is currently unused, and we build with -Werror.
@@ -266,7 +274,6 @@ void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
#endif
#endif
-// malloc_introspection callbacks. I'm not clear on what all of these do.
kern_return_t mi_enumerator(task_t task, void *,
unsigned type_mask, vm_address_t zone_address,
memory_reader_t reader,
@@ -282,12 +289,10 @@ size_t mi_good_size(malloc_zone_t *zone, size_t size) {
boolean_t mi_check(malloc_zone_t *zone) {
UNIMPLEMENTED();
- return true;
}
void mi_print(malloc_zone_t *zone, boolean_t verbose) {
UNIMPLEMENTED();
- return;
}
void mi_log(malloc_zone_t *zone, void *address) {
@@ -302,17 +307,12 @@ void mi_force_unlock(malloc_zone_t *zone) {
asan_mz_force_unlock();
}
-// This function is currently unused, and we build with -Werror.
-#if 0
void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
- // TODO(csilvers): figure out how to fill these out
- // TODO(glider): port this from tcmalloc when ready.
- stats->blocks_in_use = 0;
- stats->size_in_use = 0;
- stats->max_size_in_use = 0;
- stats->size_allocated = 0;
+ AsanMallocStats malloc_stats;
+ asanThreadRegistry().FillMallocStatistics(&malloc_stats);
+ CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
+ internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
}
-#endif
#if defined(MAC_OS_X_VERSION_10_6) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@@ -327,7 +327,7 @@ boolean_t mi_zone_locked(malloc_zone_t *zone) {
extern int __CFRuntimeClassTableSize;
namespace __asan {
-void ReplaceCFAllocator() {
+void MaybeReplaceCFAllocator() {
static CFAllocatorContext asan_context = {
/*version*/ 0, /*info*/ &asan_zone,
/*retain*/ 0, /*release*/ 0,
@@ -338,7 +338,7 @@ void ReplaceCFAllocator() {
/*preferredSize*/ 0 };
if (!cf_asan)
cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
- if (CFAllocatorGetDefault() != cf_asan)
+ if (flags()->replace_cfallocator && CFAllocatorGetDefault() != cf_asan)
CFAllocatorSetDefault(cf_asan);
}
@@ -354,6 +354,7 @@ void ReplaceSystemMalloc() {
asan_introspection.log = &mi_log;
asan_introspection.force_lock = &mi_force_lock;
asan_introspection.force_unlock = &mi_force_unlock;
+ asan_introspection.statistics = &mi_statistics;
internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));
@@ -405,16 +406,14 @@ void ReplaceSystemMalloc() {
// Make sure the default allocator was replaced.
CHECK(malloc_default_zone() == &asan_zone);
- if (flags()->replace_cfallocator) {
- // If __CFInitialize() hasn't been called yet, cf_asan will be created and
- // installed as the default allocator after __CFInitialize() finishes (see
- // the interceptor for __CFInitialize() above). Otherwise install cf_asan
- // right now. On both Snow Leopard and Lion __CFInitialize() calls
- // __CFAllocatorInitialize(), which initializes the _base._cfisa field of
- // the default allocators we check here.
- if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
- ReplaceCFAllocator();
- }
+ // If __CFInitialize() hasn't been called yet, cf_asan will be created and
+ // installed as the default allocator after __CFInitialize() finishes (see
+ // the interceptor for __CFInitialize() above). Otherwise install cf_asan
+ // right now. On both Snow Leopard and Lion __CFInitialize() calls
+ // __CFAllocatorInitialize(), which initializes the _base._cfisa field of
+ // the default allocators we check here.
+ if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
+ MaybeReplaceCFAllocator();
}
}
} // namespace __asan