blob: b2618d7297f4b6ef428a38ecca256ea2f93fa671 [file] [log] [blame]
Kostya Serebryany1e172b42011-11-30 01:07:02 +00001//===-- asan_mac.cc -------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Mac-specific details.
13//===----------------------------------------------------------------------===//
14
Evgeniy Stepanov24e13722013-03-19 14:33:38 +000015#include "sanitizer_common/sanitizer_platform.h"
Evgeniy Stepanov30e110e2013-03-19 14:54:17 +000016#if SANITIZER_MAC
Kostya Serebryany1e172b42011-11-30 01:07:02 +000017
Alexey Samsonov64ce2db2012-03-21 12:03:44 +000018#include "asan_interceptors.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000019#include "asan_internal.h"
Alexander Potapenko895b3872012-02-13 17:14:31 +000020#include "asan_mapping.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000021#include "asan_stack.h"
22#include "asan_thread.h"
Alexander Potapenko31f78fd2013-07-16 09:29:48 +000023#include "sanitizer_common/sanitizer_atomic.h"
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000024#include "sanitizer_common/sanitizer_libc.h"
Stephen Hines2d1fdb22014-05-28 23:58:16 -070025#include "sanitizer_common/sanitizer_mac.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000026
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +000027#include <crt_externs.h> // for _NSGetArgv
28#include <dlfcn.h> // for dladdr()
Alexander Potapenko8a34d382012-01-18 11:16:05 +000029#include <mach-o/dyld.h>
Kostya Serebryany9b993e82012-01-30 22:11:04 +000030#include <mach-o/loader.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000031#include <sys/mman.h>
Kostya Serebryanyef14ff62012-01-06 02:12:25 +000032#include <sys/resource.h>
Alexander Potapenko59dc5782012-01-31 13:19:18 +000033#include <sys/sysctl.h>
Kostya Serebryany9107c262012-01-06 19:11:09 +000034#include <sys/ucontext.h>
Kostya Serebryanya874fe52011-12-28 23:28:54 +000035#include <fcntl.h>
Alexander Potapenkoe205a9d2012-06-20 22:29:09 +000036#include <pthread.h>
37#include <stdlib.h> // for free()
Kostya Serebryany1e172b42011-11-30 01:07:02 +000038#include <unistd.h>
Kostya Serebryanyd55f5f82012-01-10 21:24:40 +000039#include <libkern/OSAtomic.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000040
41namespace __asan {
42
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070043void InitializePlatformInterceptors() {}
Alexander Potapenko31f78fd2013-07-16 09:29:48 +000044
Alexey Samsonov38dd4ed2012-03-20 10:54:40 +000045bool PlatformHasDifferentMemcpyAndMemmove() {
46 // On OS X 10.7 memcpy() and memmove() are both resolved
47 // into memmove$VARIANT$sse42.
48 // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34.
49 // TODO(glider): need to check dynamically that memcpy() and memmove() are
50 // actually the same function.
51 return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
52}
53
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +000054extern "C"
55void __asan_init();
56
57static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
Alexander Potapenkofe984cc2013-02-15 16:10:49 +000058LowLevelAllocator allocator_for_env;
59
60// Change the value of the env var |name|, leaking the original value.
61// If |name_value| is NULL, the variable is deleted from the environment,
62// otherwise the corresponding "NAME=value" string is replaced with
63// |name_value|.
64void LeakyResetEnv(const char *name, const char *name_value) {
65 char ***env_ptr = _NSGetEnviron();
66 CHECK(env_ptr);
67 char **environ = *env_ptr;
68 CHECK(environ);
69 uptr name_len = internal_strlen(name);
70 while (*environ != 0) {
71 uptr len = internal_strlen(*environ);
72 if (len > name_len) {
73 const char *p = *environ;
74 if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
75 // Match.
76 if (name_value) {
77 // Replace the old value with the new one.
78 *environ = const_cast<char*>(name_value);
79 } else {
80 // Shift the subsequent pointers back.
81 char **del = environ;
82 do {
83 del[0] = del[1];
Kostya Serebryany366984e2013-02-19 11:30:25 +000084 } while (*del++);
Alexander Potapenkofe984cc2013-02-15 16:10:49 +000085 }
86 }
87 }
88 environ++;
89 }
90}
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +000091
Stephen Hines86277eb2015-03-23 12:06:32 -070092static bool reexec_disabled = false;
93
94void DisableReexec() {
95 reexec_disabled = true;
96}
97
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +000098void MaybeReexec() {
Stephen Hines86277eb2015-03-23 12:06:32 -070099 if (reexec_disabled) return;
100
Alexander Potapenko69563982013-02-05 15:57:12 +0000101 // Make sure the dynamic ASan runtime library is preloaded so that the
102 // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
103 // ourselves.
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +0000104 Dl_info info;
Alexey Samsonov4ea14c22012-09-12 14:10:14 +0000105 CHECK(dladdr((void*)((uptr)__asan_init), &info));
Alexander Potapenkofe984cc2013-02-15 16:10:49 +0000106 char *dyld_insert_libraries =
107 const_cast<char*>(GetEnv(kDyldInsertLibraries));
Alexey Samsonov180e9882013-02-15 19:22:49 +0000108 uptr old_env_len = dyld_insert_libraries ?
Alexander Potapenkofe984cc2013-02-15 16:10:49 +0000109 internal_strlen(dyld_insert_libraries) : 0;
Alexey Samsonove6b91fd2013-02-15 19:02:32 +0000110 uptr fname_len = internal_strlen(info.dli_fname);
Stephen Hines86277eb2015-03-23 12:06:32 -0700111 const char *dylib_name = StripModuleName(info.dli_fname);
112 uptr dylib_name_len = internal_strlen(dylib_name);
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +0000113 if (!dyld_insert_libraries ||
Stephen Hines86277eb2015-03-23 12:06:32 -0700114 !REAL(strstr)(dyld_insert_libraries, dylib_name)) {
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +0000115 // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
116 // library.
117 char program_name[1024];
118 uint32_t buf_size = sizeof(program_name);
119 _NSGetExecutablePath(program_name, &buf_size);
Alexander Potapenkofe984cc2013-02-15 16:10:49 +0000120 char *new_env = const_cast<char*>(info.dli_fname);
Alexander Potapenkoeb5f4272013-02-13 17:52:55 +0000121 if (dyld_insert_libraries) {
122 // Append the runtime dylib name to the existing value of
123 // DYLD_INSERT_LIBRARIES.
Alexander Potapenkofe984cc2013-02-15 16:10:49 +0000124 new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
Alexander Potapenkoeb5f4272013-02-13 17:52:55 +0000125 internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
126 new_env[old_env_len] = ':';
127 // Copy fname_len and add a trailing zero.
Kostya Serebryany8da17ea2013-02-14 06:54:51 +0000128 internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
129 fname_len + 1);
Alexander Potapenkofe984cc2013-02-15 16:10:49 +0000130 // Ok to use setenv() since the wrappers don't depend on the value of
131 // asan_inited.
Alexander Potapenkoeb5f4272013-02-13 17:52:55 +0000132 setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
133 } else {
134 // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
135 setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
136 }
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700137 VReport(1, "exec()-ing the program with\n");
138 VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
139 VReport(1, "to enable ASan wrappers.\n");
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +0000140 execv(program_name, *_NSGetArgv());
Alexander Potapenkofe984cc2013-02-15 16:10:49 +0000141
Stephen Hines86277eb2015-03-23 12:06:32 -0700142 // We get here only if execv() failed.
143 Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
144 "which is required for ASan to work. ASan tried to set the "
145 "environment variable and re-execute itself, but execv() failed, "
146 "possibly because of sandbox restrictions. Make sure to launch the "
147 "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
148 CHECK("execv failed" && 0);
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +0000149 }
Stephen Hines86277eb2015-03-23 12:06:32 -0700150
151 // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
152 // the dylib from the environment variable, because interceptors are installed
153 // and we don't want our children to inherit the variable.
154
155 uptr env_name_len = internal_strlen(kDyldInsertLibraries);
156 // Allocate memory to hold the previous env var name, its value, the '='
157 // sign and the '\0' char.
158 char *new_env = (char*)allocator_for_env.Allocate(
159 old_env_len + 2 + env_name_len);
160 CHECK(new_env);
161 internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
162 internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
163 new_env[env_name_len] = '=';
164 char *new_env_pos = new_env + env_name_len + 1;
165
166 // Iterate over colon-separated pieces of |dyld_insert_libraries|.
167 char *piece_start = dyld_insert_libraries;
168 char *piece_end = NULL;
169 char *old_env_end = dyld_insert_libraries + old_env_len;
170 do {
171 if (piece_start[0] == ':') piece_start++;
172 piece_end = REAL(strchr)(piece_start, ':');
173 if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
174 if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
175 uptr piece_len = piece_end - piece_start;
176
177 char *filename_start =
178 (char *)internal_memrchr(piece_start, '/', piece_len);
179 uptr filename_len = piece_len;
180 if (filename_start) {
181 filename_start += 1;
182 filename_len = piece_len - (filename_start - piece_start);
183 } else {
184 filename_start = piece_start;
185 }
186
187 // If the current piece isn't the runtime library name,
188 // append it to new_env.
189 if ((dylib_name_len != filename_len) ||
190 (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
191 if (new_env_pos != new_env + env_name_len + 1) {
192 new_env_pos[0] = ':';
193 new_env_pos++;
194 }
195 internal_strncpy(new_env_pos, piece_start, piece_len);
196 new_env_pos += piece_len;
197 }
198 // Move on to the next piece.
199 piece_start = piece_end;
200 } while (piece_start < old_env_end);
201
202 // Can't use setenv() here, because it requires the allocator to be
203 // initialized.
204 // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
205 // a separate function called after InitializeAllocator().
206 if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
207 LeakyResetEnv(kDyldInsertLibraries, new_env);
Alexander Potapenkoeb8c46e2012-08-24 09:22:05 +0000208}
209
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000210// No-op. Mac does not support static linkage anyway.
211void *AsanDoesNotSupportStaticLinkage() {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000212 return 0;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000213}
214
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700215// No-op. Mac does not support static linkage anyway.
216void AsanCheckDynamicRTPrereqs() {}
217
218// No-op. Mac does not support static linkage anyway.
219void AsanCheckIncompatibleRT() {}
220
Alexander Potapenko75b19eb2012-07-23 14:07:58 +0000221void AsanPlatformThreadInit() {
Alexander Potapenko75b19eb2012-07-23 14:07:58 +0000222}
223
Alexey Samsonov57db4ba2013-01-17 15:45:28 +0000224void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
Alexey Samsonovf3950c62012-11-23 10:14:44 +0000225 UNIMPLEMENTED();
226}
227
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000228// Support for the following functions from libdispatch on Mac OS:
229// dispatch_async_f()
230// dispatch_async()
231// dispatch_sync_f()
232// dispatch_sync()
233// dispatch_after_f()
234// dispatch_after()
235// dispatch_group_async_f()
236// dispatch_group_async()
237// TODO(glider): libdispatch API contains other functions that we don't support
238// yet.
239//
240// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
241// they can cause jobs to run on a thread different from the current one.
242// TODO(glider): if so, we need a test for this (otherwise we should remove
243// them).
244//
245// The following functions use dispatch_barrier_async_f() (which isn't a library
246// function but is exported) and are thus supported:
247// dispatch_source_set_cancel_handler_f()
248// dispatch_source_set_cancel_handler()
249// dispatch_source_set_event_handler_f()
250// dispatch_source_set_event_handler()
251//
252// The reference manual for Grand Central Dispatch is available at
253// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
254// The implementation details are at
255// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
256
Alexey Samsonovf7ceaad2012-04-09 16:45:18 +0000257typedef void* dispatch_group_t;
258typedef void* dispatch_queue_t;
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000259typedef void* dispatch_source_t;
Kostya Serebryanyee392552012-05-31 15:02:07 +0000260typedef u64 dispatch_time_t;
Alexey Samsonovf7ceaad2012-04-09 16:45:18 +0000261typedef void (*dispatch_function_t)(void *block);
Alexey Samsonov5cf832d2012-03-21 12:29:54 +0000262typedef void* (*worker_t)(void *block);
263
264// A wrapper for the ObjC blocks used to support libdispatch.
265typedef struct {
266 void *block;
267 dispatch_function_t func;
Kostya Serebryanye0cff0b2012-06-06 15:06:58 +0000268 u32 parent_tid;
Alexey Samsonov5cf832d2012-03-21 12:29:54 +0000269} asan_block_context_t;
270
Timur Iskhodzhanovb157c672013-03-28 21:16:09 +0000271ALWAYS_INLINE
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000272void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
Alexey Samsonovc25e62b2013-03-20 10:11:24 +0000273 AsanThread *t = GetCurrentThread();
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000274 if (!t) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700275 t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
276 parent_tid, stack, /* detached */ true);
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000277 t->Init();
Alexey Samsonovdef1be92013-03-21 11:23:41 +0000278 asanThreadRegistry().StartThread(t->tid(), 0, 0);
Alexey Samsonovc25e62b2013-03-20 10:11:24 +0000279 SetCurrentThread(t);
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000280 }
281}
282
Alexander Potapenko2483ce32012-08-20 11:59:26 +0000283// For use by only those functions that allocated the context via
284// alloc_asan_context().
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000285extern "C"
286void asan_dispatch_call_block_and_release(void *block) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000287 GET_STACK_TRACE_THREAD;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000288 asan_block_context_t *context = (asan_block_context_t*)block;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700289 VReport(2,
290 "asan_dispatch_call_block_and_release(): "
291 "context: %p, pthread_self: %p\n",
292 block, pthread_self());
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000293 asan_register_worker_thread(context->parent_tid, &stack);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000294 // Call the original dispatcher for the block.
295 context->func(context->block);
Kostya Serebryanyfe6d9162012-12-21 08:53:59 +0000296 asan_free(context, &stack, FROM_MALLOC);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000297}
298
299} // namespace __asan
300
301using namespace __asan; // NOLINT
302
303// Wrap |ctxt| and |func| into an asan_block_context_t.
304// The caller retains control of the allocated context.
305extern "C"
306asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
Stephen Hines6d186232014-11-26 17:56:19 -0800307 BufferedStackTrace *stack) {
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000308 asan_block_context_t *asan_ctxt =
309 (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
310 asan_ctxt->block = ctxt;
311 asan_ctxt->func = func;
Alexey Samsonovc25e62b2013-03-20 10:11:24 +0000312 asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000313 return asan_ctxt;
314}
315
Alexander Potapenkob09dd342012-08-20 09:25:10 +0000316// Define interceptor for dispatch_*_f function with the three most common
317// parameters: dispatch_queue_t, context, dispatch_function_t.
318#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
319 INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
320 dispatch_function_t func) { \
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000321 GET_STACK_TRACE_THREAD; \
Alexander Potapenkob09dd342012-08-20 09:25:10 +0000322 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
Stephen Hines86277eb2015-03-23 12:06:32 -0700323 if (Verbosity() >= 2) { \
Alexander Potapenkob09dd342012-08-20 09:25:10 +0000324 Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
325 asan_ctxt, pthread_self()); \
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700326 PRINT_CURRENT_STACK(); \
327 } \
328 return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
329 asan_dispatch_call_block_and_release); \
Kostya Serebryany0ffc2272012-08-21 06:43:44 +0000330 }
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000331
Alexander Potapenkob09dd342012-08-20 09:25:10 +0000332INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
333INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
334INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000335
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000336INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
337 dispatch_queue_t dq, void *ctxt,
338 dispatch_function_t func) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000339 GET_STACK_TRACE_THREAD;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000340 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
Stephen Hines86277eb2015-03-23 12:06:32 -0700341 if (Verbosity() >= 2) {
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000342 Report("dispatch_after_f: %p\n", asan_ctxt);
343 PRINT_CURRENT_STACK();
344 }
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000345 return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
346 asan_dispatch_call_block_and_release);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000347}
348
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000349INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
350 dispatch_queue_t dq, void *ctxt,
351 dispatch_function_t func) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000352 GET_STACK_TRACE_THREAD;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000353 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
Stephen Hines86277eb2015-03-23 12:06:32 -0700354 if (Verbosity() >= 2) {
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000355 Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
356 asan_ctxt, pthread_self());
357 PRINT_CURRENT_STACK();
358 }
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000359 REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
360 asan_dispatch_call_block_and_release);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000361}
362
Alexander Potapenko69563982013-02-05 15:57:12 +0000363#if !defined(MISSING_BLOCKS_SUPPORT)
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000364extern "C" {
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000365void dispatch_async(dispatch_queue_t dq, void(^work)(void));
366void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
367 void(^work)(void));
368void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
369 void(^work)(void));
370void dispatch_source_set_cancel_handler(dispatch_source_t ds,
371 void(^work)(void));
372void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
373}
374
375#define GET_ASAN_BLOCK(work) \
376 void (^asan_block)(void); \
Alexey Samsonovc25e62b2013-03-20 10:11:24 +0000377 int parent_tid = GetCurrentTidOrInvalid(); \
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000378 asan_block = ^(void) { \
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000379 GET_STACK_TRACE_THREAD; \
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000380 asan_register_worker_thread(parent_tid, &stack); \
381 work(); \
382 }
383
384INTERCEPTOR(void, dispatch_async,
385 dispatch_queue_t dq, void(^work)(void)) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700386 ENABLE_FRAME_POINTER;
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000387 GET_ASAN_BLOCK(work);
388 REAL(dispatch_async)(dq, asan_block);
389}
390
391INTERCEPTOR(void, dispatch_group_async,
392 dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700393 ENABLE_FRAME_POINTER;
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000394 GET_ASAN_BLOCK(work);
395 REAL(dispatch_group_async)(dg, dq, asan_block);
396}
397
398INTERCEPTOR(void, dispatch_after,
399 dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700400 ENABLE_FRAME_POINTER;
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000401 GET_ASAN_BLOCK(work);
402 REAL(dispatch_after)(when, queue, asan_block);
403}
404
405INTERCEPTOR(void, dispatch_source_set_cancel_handler,
406 dispatch_source_t ds, void(^work)(void)) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700407 if (!work) {
408 REAL(dispatch_source_set_cancel_handler)(ds, work);
409 return;
410 }
Stephen Hines6a211c52014-07-21 00:49:56 -0700411 ENABLE_FRAME_POINTER;
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000412 GET_ASAN_BLOCK(work);
413 REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
414}
415
416INTERCEPTOR(void, dispatch_source_set_event_handler,
417 dispatch_source_t ds, void(^work)(void)) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700418 ENABLE_FRAME_POINTER;
Alexander Potapenkoaf198e42012-08-23 09:34:40 +0000419 GET_ASAN_BLOCK(work);
420 REAL(dispatch_source_set_event_handler)(ds, asan_block);
421}
422#endif
423
Alexey Samsonov649a2702013-04-03 07:29:53 +0000424#endif // SANITIZER_MAC