summaryrefslogtreecommitdiff
path: root/lib/asan/asan_mac.cc
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2012-08-20 11:59:26 +0000
committerAlexander Potapenko <glider@google.com>2012-08-20 11:59:26 +0000
commit2483ce3e635515d907c0cd8c97db315142fb28db (patch)
tree6dedd439eef6e55380645da1e012b8cb0075a30a /lib/asan/asan_mac.cc
parentb09dd34786713a150fed5c5ab1529f01de0e2bc0 (diff)
downloadcompiler-rt-2483ce3e635515d907c0cd8c97db315142fb28db.tar.gz
compiler-rt-2483ce3e635515d907c0cd8c97db315142fb28db.tar.bz2
compiler-rt-2483ce3e635515d907c0cd8c97db315142fb28db.tar.xz
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/asan_mac.cc')
-rw-r--r--lib/asan/asan_mac.cc62
1 files changed, 62 insertions, 0 deletions
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index bda4e228..0118da8e 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) {