Dynamic interceptors for dispatch_async and dispatch_after.

llvm-svn: 162202
This commit is contained in:
Alexander Potapenko 2012-08-20 11:59:26 +00:00
parent 1b07ab51e4
commit 02e6f03236
3 changed files with 76 additions and 0 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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),