diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 5cbf3f3e6dc5..81d261ef9e4f 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -43,24 +43,25 @@ // After interception, the calls to system functions will be substituted by // calls to our interceptors. We store pointers to system function f() // in __asan::real_f(). -// -// TODO(glider): mach_override_ptr() tends to spend too much time -// in allocateBranchIsland(). This should be ok for real-word -// application, but slows down our tests which fork too many children. #ifdef __APPLE__ #include "mach_override/mach_override.h" #define WRAPPER_NAME(x) "wrap_"#x -#define OVERRIDE_FUNCTION(oldfunc, newfunc) \ - CHECK(0 == __asan_mach_override_ptr((void*)(oldfunc), \ - (void*)(newfunc), \ - (void**)&real_##oldfunc)); \ - CHECK(real_##oldfunc != NULL); +#define OVERRIDE_FUNCTION(oldfunc, newfunc) \ + do {CHECK(0 == __asan_mach_override_ptr_custom((void*)(oldfunc), \ + (void*)(newfunc), \ + (void**)&real_##oldfunc, \ + __asan_allocate_island, \ + __asan_deallocate_island)); \ + CHECK(real_##oldfunc != NULL); } while(0) -#define OVERRIDE_FUNCTION_IF_EXISTS(oldfunc, newfunc) \ - do { __asan_mach_override_ptr((void*)(oldfunc), \ - (void*)(newfunc), \ - (void**)&real_##oldfunc); } while (0) +#define OVERRIDE_FUNCTION_IF_EXISTS(oldfunc, newfunc) \ + do { __asan_mach_override_ptr_custom((void*)(oldfunc), \ + (void*)(newfunc), \ + (void**)&real_##oldfunc, \ + __asan_allocate_island, \ + __asan_deallocate_island); \ + } while (0) #define INTERCEPT_FUNCTION(func) \ OVERRIDE_FUNCTION(func, WRAP(func)) diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index 4bfe74cb4877..0bf978214b82 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -32,6 +32,8 @@ namespace __asan { +void *island_allocator_pos = NULL; + extern dispatch_async_f_f real_dispatch_async_f; extern dispatch_sync_f_f real_dispatch_sync_f; extern dispatch_after_f_f real_dispatch_after_f; @@ -172,6 +174,37 @@ void AsanLock::Unlock() { OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); } +// The range of pages to be used by __asan_mach_override_ptr for escape +// islands. +// TODO(glider): instead of mapping a fixed range we must find a range of +// unmapped pages in vmmap and take them. +#define kIslandEnd (0x7fffffdf0000 - kPageSize) +#define kIslandBeg (kIslandEnd - 256 * kPageSize) + +extern "C" +mach_error_t __asan_allocate_island(void **ptr, + size_t unused_size, + void *unused_hint) { + if (!island_allocator_pos) { + if ((void*)-1 == asan_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, + -1, 0)) { + return KERN_NO_SPACE; + } + island_allocator_pos = (void*)kIslandBeg; + }; + *ptr = island_allocator_pos; + island_allocator_pos = (char*)island_allocator_pos + kPageSize; + return err_none; +} + +extern "C" +mach_error_t __asan_deallocate_island(void *ptr) { + // Do nothing. + // TODO(glider): allow to free and reuse the island memory. + return err_none; +} // Support for the following functions from libdispatch on Mac OS: // dispatch_async_f() diff --git a/compiler-rt/lib/asan/asan_mac.h b/compiler-rt/lib/asan/asan_mac.h index 32739e766cc7..7c941f81b837 100644 --- a/compiler-rt/lib/asan/asan_mac.h +++ b/compiler-rt/lib/asan/asan_mac.h @@ -20,6 +20,7 @@ // TODO(glider): need to check if the OS X version is 10.6 or greater. #include +#include #include typedef void* pthread_workqueue_t; @@ -54,6 +55,15 @@ typedef struct { extern "C" { + +// Allocate memory for the escape island. This cannot be moved to +// mach_override, because the allocator needs to know about the ASan shadow +// mappings. +// TODO(glider): in order to place a relative jump the allocated memory should +// be within 2 Gb from the hint address. +mach_error_t __asan_allocate_island(void **ptr, size_t unused_size, void *unused_hint); +mach_error_t __asan_deallocate_island(void *ptr); + // dispatch_barrier_async_f() is not declared in . void dispatch_barrier_async_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func);