summaryrefslogtreecommitdiff
path: root/lib/asan
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
parentb09dd34786713a150fed5c5ab1529f01de0e2bc0 (diff)
downloadcompiler-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.h6
-rw-r--r--lib/asan/asan_mac.cc62
-rw-r--r--lib/asan/dynamic/asan_interceptors_dynamic.cc8
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),