diff options
author | Alexander Potapenko <glider@google.com> | 2012-08-20 11:59:26 +0000 |
---|---|---|
committer | Alexander Potapenko <glider@google.com> | 2012-08-20 11:59:26 +0000 |
commit | 2483ce3e635515d907c0cd8c97db315142fb28db (patch) | |
tree | 6dedd439eef6e55380645da1e012b8cb0075a30a /lib/asan | |
parent | b09dd34786713a150fed5c5ab1529f01de0e2bc0 (diff) | |
download | compiler-rt-2483ce3e635515d907c0cd8c97db315142fb28db.tar.gz |
Dynamic interceptors for dispatch_async and dispatch_after.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@162202 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/asan')
-rw-r--r-- | lib/asan/asan_intercepted_functions.h | 6 | ||||
-rw-r--r-- | lib/asan/asan_mac.cc | 62 | ||||
-rw-r--r-- | lib/asan/dynamic/asan_interceptors_dynamic.cc | 8 |
3 files changed, 76 insertions, 0 deletions
diff --git a/lib/asan/asan_intercepted_functions.h b/lib/asan/asan_intercepted_functions.h index 71cc2ccfb..0a18818b5 100644 --- a/lib/asan/asan_intercepted_functions.h +++ b/lib/asan/asan_intercepted_functions.h @@ -198,6 +198,12 @@ DECLARE_FUNCTION_AND_WRAPPER(void, __CFInitialize); DECLARE_FUNCTION_AND_WRAPPER(CFStringRef, CFStringCreateCopy, CFAllocatorRef alloc, CFStringRef str); DECLARE_FUNCTION_AND_WRAPPER(void, free, void* ptr); +#if MAC_INTERPOSE_FUNCTIONS +DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async, + dispatch_queue_t dq, void (^work)(void)); +DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after, + dispatch_queue_t dq, void (^work)(void)); +#endif // MAC_INTERPOSE_FUNCTIONS #endif // __APPLE__ } // extern "C" #endif diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index bda4e2287..0118da8ed 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -241,6 +241,8 @@ int pthread_workqueue_additem_np(pthread_workqueue_t workq, pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp); } // extern "C" +// For use by only those functions that allocated the context via +// alloc_asan_context(). extern "C" void asan_dispatch_call_block_and_release(void *block) { GET_STACK_TRACE_HERE(kStackTraceMax); @@ -312,6 +314,66 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, asan_dispatch_call_block_and_release); } +#if MAC_INTERPOSE_FUNCTIONS +// dispatch_async and TODO tailcall the corresponding dispatch_*_f functions. +// When wrapping functions with mach_override, they are intercepted +// automatically. But with dylib interposition this does not work, because the +// calls within the same library are not interposed. +// Therefore we need to re-implement dispatch_async and friends. + +// See dispatch/dispatch.h. +#define DISPATCH_TIME_FOREVER (~0ull) +typedef void (^dispatch_block_t)(void); + +// See +// http://www.opensource.apple.com/source/libdispatch/libdispatch-228.18/src/init.c +// for the implementation of _dispatch_call_block_copy_and_release(). +static void _dispatch_call_block_and_release(void *block) { + void (^b)(void) = (dispatch_block_t)block; + b(); + _Block_release(b); +} + +// See +// http://www.opensource.apple.com/source/libdispatch/libdispatch-228.18/src/internal.h +#define fastpath(x) ((typeof(x))__builtin_expect((long)(x), ~0l)) + +// See +// http://www.opensource.apple.com/source/libdispatch/libdispatch-228.18/src/init.c +static dispatch_block_t _dispatch_Block_copy(dispatch_block_t db) { + dispatch_block_t rval; + if (fastpath(db)) { + while (!fastpath(rval = Block_copy(db))) { + sleep(1); + } + return rval; + } + CHECK(0 && "NULL was passed where a block should have been"); + return (dispatch_block_t)NULL; // Unreachable. +} + +// See +// http://www.opensource.apple.com/source/libdispatch/libdispatch-228.18/src/queue.c +// for the implementation of dispatch_async(), dispatch_sync(), +// dispatch_after(). +INTERCEPTOR(void, dispatch_async, + dispatch_queue_t dq, dispatch_block_t work) { + WRAP(dispatch_async_f)(dq, _dispatch_Block_copy(work), + _dispatch_call_block_and_release); +} + +INTERCEPTOR(void, dispatch_after, + dispatch_time_t when, dispatch_queue_t queue, + dispatch_block_t work) { + if (when == DISPATCH_TIME_FOREVER) { + CHECK(0 && "dispatch_after() called with 'when' == infinity"); + return; // Unreachable. + } + WRAP(dispatch_after_f)(when, queue, _dispatch_Block_copy(work), + _dispatch_call_block_and_release); +} +#endif + INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { diff --git a/lib/asan/dynamic/asan_interceptors_dynamic.cc b/lib/asan/dynamic/asan_interceptors_dynamic.cc index 787446d9a..009d50381 100644 --- a/lib/asan/dynamic/asan_interceptors_dynamic.cc +++ b/lib/asan/dynamic/asan_interceptors_dynamic.cc @@ -19,6 +19,11 @@ namespace __asan { +#if !MAC_INTERPOSE_FUNCTIONS +# error \ + Dynamic interposing library should be built with -DMAC_INTERPOSE_FUNCTIONS +#endif + #define INTERPOSE_FUNCTION(function) \ { reinterpret_cast<const uptr>(WRAP(function)), \ reinterpret_cast<const uptr>(function) } @@ -87,6 +92,9 @@ const interpose_substitution substitutions[] INTERPOSE_FUNCTION(dispatch_barrier_async_f), INTERPOSE_FUNCTION(dispatch_group_async_f), + INTERPOSE_FUNCTION(dispatch_async), + INTERPOSE_FUNCTION(dispatch_after), + INTERPOSE_FUNCTION(__CFInitialize), INTERPOSE_FUNCTION(CFStringCreateCopy), INTERPOSE_FUNCTION(free), |