forked from OSchip/llvm-project
This patch adds two methods, __asan_allocate_island and __asan_deallocate_island
and switches our interceptors to using them instead of the default vm_allocate-based approach used by mach_override_ptr. To simplify the code, a fixed memory mapping is used for the allocation pool -- note that we can't mmap an arbitrary chunk of memory, because the shadow memory hasn't been mapped yet (for the reasons discussed in http://code.google.com/p/address-sanitizer/issues/detail?id=24, we cannot map the shadow earlier) The patch drops the program startup time from several second to half a second, which speeds up the execution of ASan tests noticeably. Because of the virtual memory size occupied by the programs it's hard to speed up the shutdown time, which would've also helped the tests. llvm-svn: 148116
This commit is contained in:
parent
9301db4baa
commit
bd53f597de
|
@ -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))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
// TODO(glider): need to check if the OS X version is 10.6 or greater.
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <mach/mach_error.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
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 <dispatch/dispatch.h>.
|
||||
void dispatch_barrier_async_f(dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
|
|
Loading…
Reference in New Issue