1 //===-- asan_mac.cc -------------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of AddressSanitizer, an address sanity checker.
10 // Mac-specific details.
11 //===----------------------------------------------------------------------===//
15 #include "asan_interceptors.h"
16 #include "asan_internal.h"
18 #include "asan_mapping.h"
19 #include "asan_stack.h"
20 #include "asan_thread.h"
21 #include "asan_thread_registry.h"
22 #include "sanitizer_common/sanitizer_libc.h"
24 #include <crt_externs.h> // for _NSGetArgv
25 #include <dlfcn.h> // for dladdr()
26 #include <mach-o/dyld.h>
27 #include <mach-o/loader.h>
29 #include <sys/resource.h>
30 #include <sys/sysctl.h>
31 #include <sys/ucontext.h>
34 #include <stdlib.h> // for free()
36 #include <libkern/OSAtomic.h>
37 #include <CoreFoundation/CFString.h>
41 void GetPcSpBp(void *context
, uptr
*pc
, uptr
*sp
, uptr
*bp
) {
42 ucontext_t
*ucontext
= (ucontext_t
*)context
;
43 # if SANITIZER_WORDSIZE == 64
44 *pc
= ucontext
->uc_mcontext
->__ss
.__rip
;
45 *bp
= ucontext
->uc_mcontext
->__ss
.__rbp
;
46 *sp
= ucontext
->uc_mcontext
->__ss
.__rsp
;
48 *pc
= ucontext
->uc_mcontext
->__ss
.__eip
;
49 *bp
= ucontext
->uc_mcontext
->__ss
.__ebp
;
50 *sp
= ucontext
->uc_mcontext
->__ss
.__esp
;
51 # endif // SANITIZER_WORDSIZE
54 int GetMacosVersion() {
55 int mib
[2] = { CTL_KERN
, KERN_OSRELEASE
};
57 uptr len
= 0, maxlen
= sizeof(version
) / sizeof(version
[0]);
58 for (uptr i
= 0; i
< maxlen
; i
++) version
[i
] = '\0';
59 // Get the version length.
60 CHECK(sysctl(mib
, 2, 0, &len
, 0, 0) != -1);
62 CHECK(sysctl(mib
, 2, version
, &len
, 0, 0) != -1);
64 case '9': return MACOS_VERSION_LEOPARD
;
67 case '0': return MACOS_VERSION_SNOW_LEOPARD
;
68 case '1': return MACOS_VERSION_LION
;
69 case '2': return MACOS_VERSION_MOUNTAIN_LION
;
70 default: return MACOS_VERSION_UNKNOWN
;
73 default: return MACOS_VERSION_UNKNOWN
;
77 bool PlatformHasDifferentMemcpyAndMemmove() {
78 // On OS X 10.7 memcpy() and memmove() are both resolved
79 // into memmove$VARIANT$sse42.
80 // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34.
81 // TODO(glider): need to check dynamically that memcpy() and memmove() are
82 // actually the same function.
83 return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD
;
89 static const char kDyldInsertLibraries
[] = "DYLD_INSERT_LIBRARIES";
92 if (!flags()->allow_reexec
) return;
93 #if MAC_INTERPOSE_FUNCTIONS
94 // If the program is linked with the dynamic ASan runtime library, make sure
95 // the library is preloaded so that the wrappers work. If it is not, set
96 // DYLD_INSERT_LIBRARIES and re-exec ourselves.
98 CHECK(dladdr((void*)((uptr
)__asan_init
), &info
));
99 const char *dyld_insert_libraries
= GetEnv(kDyldInsertLibraries
);
100 if (!dyld_insert_libraries
||
101 !REAL(strstr
)(dyld_insert_libraries
, info
.dli_fname
)) {
102 // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
104 char program_name
[1024];
105 uint32_t buf_size
= sizeof(program_name
);
106 _NSGetExecutablePath(program_name
, &buf_size
);
107 // Ok to use setenv() since the wrappers don't depend on the value of
109 setenv(kDyldInsertLibraries
, info
.dli_fname
, /*overwrite*/0);
110 if (flags()->verbosity
>= 1) {
111 Report("exec()-ing the program with\n");
112 Report("%s=%s\n", kDyldInsertLibraries
, info
.dli_fname
);
113 Report("to enable ASan wrappers.\n");
114 Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
116 execv(program_name
, *_NSGetArgv());
118 #endif // MAC_INTERPOSE_FUNCTIONS
119 // If we're not using the dynamic runtime, do nothing.
122 // No-op. Mac does not support static linkage anyway.
123 void *AsanDoesNotSupportStaticLinkage() {
127 bool AsanInterceptsSignal(int signum
) {
128 return (signum
== SIGSEGV
|| signum
== SIGBUS
) && flags()->handle_segv
;
131 void AsanPlatformThreadInit() {
132 // For the first program thread, we can't replace the allocator before
133 // __CFInitialize() has been called. If it hasn't, we'll call
134 // MaybeReplaceCFAllocator() later on this thread.
135 // For other threads __CFInitialize() has been called before their creation.
136 // See also asan_malloc_mac.cc.
137 if (((CFRuntimeBase
*)kCFAllocatorSystemDefault
)->_cfisa
) {
138 MaybeReplaceCFAllocator();
142 AsanLock::AsanLock(LinkerInitialized
) {
143 // We assume that OS_SPINLOCK_INIT is zero
146 void AsanLock::Lock() {
147 CHECK(sizeof(OSSpinLock
) <= sizeof(opaque_storage_
));
148 CHECK(OS_SPINLOCK_INIT
== 0);
149 CHECK(owner_
!= (uptr
)pthread_self());
150 OSSpinLockLock((OSSpinLock
*)&opaque_storage_
);
152 owner_
= (uptr
)pthread_self();
155 void AsanLock::Unlock() {
156 CHECK(owner_
== (uptr
)pthread_self());
158 OSSpinLockUnlock((OSSpinLock
*)&opaque_storage_
);
161 void GetStackTrace(StackTrace
*stack
, uptr max_s
, uptr pc
, uptr bp
) {
163 stack
->trace
[0] = pc
;
165 stack
->max_size
= max_s
;
166 if (!asan_inited
) return;
167 if (AsanThread
*t
= asanThreadRegistry().GetCurrent())
168 stack
->FastUnwindStack(pc
, bp
, t
->stack_top(), t
->stack_bottom());
172 void ClearShadowMemoryForContext(void *context
) {
176 // The range of pages to be used for escape islands.
177 // TODO(glider): instead of mapping a fixed range we must find a range of
178 // unmapped pages in vmmap and take them.
179 // These constants were chosen empirically and may not work if the shadow
180 // memory layout changes. Unfortunately they do necessarily depend on
181 // kHighMemBeg or kHighMemEnd.
182 static void *island_allocator_pos
= 0;
184 #if SANITIZER_WORDSIZE == 32
185 # define kIslandEnd (0xffdf0000 - GetPageSizeCached())
186 # define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
188 # define kIslandEnd (0x7fffffdf0000 - GetPageSizeCached())
189 # define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
193 mach_error_t
__interception_allocate_island(void **ptr
,
196 if (!island_allocator_pos
) {
197 island_allocator_pos
=
198 internal_mmap((void*)kIslandBeg
, kIslandEnd
- kIslandBeg
,
199 PROT_READ
| PROT_WRITE
| PROT_EXEC
,
200 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
,
202 if (island_allocator_pos
!= (void*)kIslandBeg
) {
203 return KERN_NO_SPACE
;
205 if (flags()->verbosity
) {
206 Report("Mapped pages %p--%p for branch islands.\n",
207 (void*)kIslandBeg
, (void*)kIslandEnd
);
209 // Should not be very performance-critical.
210 internal_memset(island_allocator_pos
, 0xCC, kIslandEnd
- kIslandBeg
);
212 *ptr
= island_allocator_pos
;
213 island_allocator_pos
= (char*)island_allocator_pos
+ GetPageSizeCached();
214 if (flags()->verbosity
) {
215 Report("Branch island allocated at %p\n", *ptr
);
221 mach_error_t
__interception_deallocate_island(void *ptr
) {
223 // TODO(glider): allow to free and reuse the island memory.
227 // Support for the following functions from libdispatch on Mac OS:
228 // dispatch_async_f()
232 // dispatch_after_f()
234 // dispatch_group_async_f()
235 // dispatch_group_async()
236 // TODO(glider): libdispatch API contains other functions that we don't support
239 // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
240 // they can cause jobs to run on a thread different from the current one.
241 // TODO(glider): if so, we need a test for this (otherwise we should remove
244 // The following functions use dispatch_barrier_async_f() (which isn't a library
245 // function but is exported) and are thus supported:
246 // dispatch_source_set_cancel_handler_f()
247 // dispatch_source_set_cancel_handler()
248 // dispatch_source_set_event_handler_f()
249 // dispatch_source_set_event_handler()
251 // The reference manual for Grand Central Dispatch is available at
252 // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
253 // The implementation details are at
254 // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
256 typedef void* pthread_workqueue_t
;
257 typedef void* pthread_workitem_handle_t
;
259 typedef void* dispatch_group_t
;
260 typedef void* dispatch_queue_t
;
261 typedef void* dispatch_source_t
;
262 typedef u64 dispatch_time_t
;
263 typedef void (*dispatch_function_t
)(void *block
);
264 typedef void* (*worker_t
)(void *block
);
266 // A wrapper for the ObjC blocks used to support libdispatch.
269 dispatch_function_t func
;
271 } asan_block_context_t
;
273 // We use extern declarations of libdispatch functions here instead
274 // of including <dispatch/dispatch.h>. This header is not present on
275 // Mac OS X Leopard and eariler, and although we don't expect ASan to
276 // work on legacy systems, it's bad to break the build of
277 // LLVM compiler-rt there.
279 void dispatch_async_f(dispatch_queue_t dq
, void *ctxt
,
280 dispatch_function_t func
);
281 void dispatch_sync_f(dispatch_queue_t dq
, void *ctxt
,
282 dispatch_function_t func
);
283 void dispatch_after_f(dispatch_time_t when
, dispatch_queue_t dq
, void *ctxt
,
284 dispatch_function_t func
);
285 void dispatch_barrier_async_f(dispatch_queue_t dq
, void *ctxt
,
286 dispatch_function_t func
);
287 void dispatch_group_async_f(dispatch_group_t group
, dispatch_queue_t dq
,
288 void *ctxt
, dispatch_function_t func
);
289 int pthread_workqueue_additem_np(pthread_workqueue_t workq
,
290 void *(*workitem_func
)(void *), void * workitem_arg
,
291 pthread_workitem_handle_t
* itemhandlep
, unsigned int *gencountp
);
295 void asan_register_worker_thread(int parent_tid
, StackTrace
*stack
) {
296 AsanThread
*t
= asanThreadRegistry().GetCurrent();
298 t
= AsanThread::Create(parent_tid
, 0, 0, stack
);
299 asanThreadRegistry().RegisterThread(t
);
301 asanThreadRegistry().SetCurrent(t
);
305 // For use by only those functions that allocated the context via
306 // alloc_asan_context().
308 void asan_dispatch_call_block_and_release(void *block
) {
309 GET_STACK_TRACE_HERE(kStackTraceMax
);
310 asan_block_context_t
*context
= (asan_block_context_t
*)block
;
311 if (flags()->verbosity
>= 2) {
312 Report("asan_dispatch_call_block_and_release(): "
313 "context: %p, pthread_self: %p\n",
314 block
, pthread_self());
316 asan_register_worker_thread(context
->parent_tid
, &stack
);
317 // Call the original dispatcher for the block.
318 context
->func(context
->block
);
319 asan_free(context
, &stack
);
322 } // namespace __asan
324 using namespace __asan
; // NOLINT
326 // Wrap |ctxt| and |func| into an asan_block_context_t.
327 // The caller retains control of the allocated context.
329 asan_block_context_t
*alloc_asan_context(void *ctxt
, dispatch_function_t func
,
331 asan_block_context_t
*asan_ctxt
=
332 (asan_block_context_t
*) asan_malloc(sizeof(asan_block_context_t
), stack
);
333 asan_ctxt
->block
= ctxt
;
334 asan_ctxt
->func
= func
;
335 asan_ctxt
->parent_tid
= asanThreadRegistry().GetCurrentTidOrInvalid();
339 // Define interceptor for dispatch_*_f function with the three most common
340 // parameters: dispatch_queue_t, context, dispatch_function_t.
341 #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
342 INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
343 dispatch_function_t func) { \
344 GET_STACK_TRACE_HERE(kStackTraceMax); \
345 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
346 if (flags()->verbosity >= 2) { \
347 Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
348 asan_ctxt, pthread_self()); \
349 PRINT_CURRENT_STACK(); \
351 return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
352 asan_dispatch_call_block_and_release); \
355 INTERCEPT_DISPATCH_X_F_3(dispatch_async_f
)
356 INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f
)
357 INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f
)
359 INTERCEPTOR(void, dispatch_after_f
, dispatch_time_t when
,
360 dispatch_queue_t dq
, void *ctxt
,
361 dispatch_function_t func
) {
362 GET_STACK_TRACE_HERE(kStackTraceMax
);
363 asan_block_context_t
*asan_ctxt
= alloc_asan_context(ctxt
, func
, &stack
);
364 if (flags()->verbosity
>= 2) {
365 Report("dispatch_after_f: %p\n", asan_ctxt
);
366 PRINT_CURRENT_STACK();
368 return REAL(dispatch_after_f
)(when
, dq
, (void*)asan_ctxt
,
369 asan_dispatch_call_block_and_release
);
372 INTERCEPTOR(void, dispatch_group_async_f
, dispatch_group_t group
,
373 dispatch_queue_t dq
, void *ctxt
,
374 dispatch_function_t func
) {
375 GET_STACK_TRACE_HERE(kStackTraceMax
);
376 asan_block_context_t
*asan_ctxt
= alloc_asan_context(ctxt
, func
, &stack
);
377 if (flags()->verbosity
>= 2) {
378 Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
379 asan_ctxt
, pthread_self());
380 PRINT_CURRENT_STACK();
382 REAL(dispatch_group_async_f
)(group
, dq
, (void*)asan_ctxt
,
383 asan_dispatch_call_block_and_release
);
386 #if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
387 // dispatch_async, dispatch_group_async and others tailcall the corresponding
388 // dispatch_*_f functions. When wrapping functions with mach_override, those
389 // dispatch_*_f are intercepted automatically. But with dylib interposition
390 // this does not work, because the calls within the same library are not
392 // Therefore we need to re-implement dispatch_async and friends.
395 // FIXME: consolidate these declarations with asan_intercepted_functions.h.
396 void dispatch_async(dispatch_queue_t dq
, void(^work
)(void));
397 void dispatch_group_async(dispatch_group_t dg
, dispatch_queue_t dq
,
399 void dispatch_after(dispatch_time_t when
, dispatch_queue_t queue
,
401 void dispatch_source_set_cancel_handler(dispatch_source_t ds
,
403 void dispatch_source_set_event_handler(dispatch_source_t ds
, void(^work
)(void));
406 #define GET_ASAN_BLOCK(work) \
407 void (^asan_block)(void); \
408 int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \
409 asan_block = ^(void) { \
410 GET_STACK_TRACE_HERE(kStackTraceMax); \
411 asan_register_worker_thread(parent_tid, &stack); \
415 INTERCEPTOR(void, dispatch_async
,
416 dispatch_queue_t dq
, void(^work
)(void)) {
417 GET_ASAN_BLOCK(work
);
418 REAL(dispatch_async
)(dq
, asan_block
);
421 INTERCEPTOR(void, dispatch_group_async
,
422 dispatch_group_t dg
, dispatch_queue_t dq
, void(^work
)(void)) {
423 GET_ASAN_BLOCK(work
);
424 REAL(dispatch_group_async
)(dg
, dq
, asan_block
);
427 INTERCEPTOR(void, dispatch_after
,
428 dispatch_time_t when
, dispatch_queue_t queue
, void(^work
)(void)) {
429 GET_ASAN_BLOCK(work
);
430 REAL(dispatch_after
)(when
, queue
, asan_block
);
433 INTERCEPTOR(void, dispatch_source_set_cancel_handler
,
434 dispatch_source_t ds
, void(^work
)(void)) {
435 GET_ASAN_BLOCK(work
);
436 REAL(dispatch_source_set_cancel_handler
)(ds
, asan_block
);
439 INTERCEPTOR(void, dispatch_source_set_event_handler
,
440 dispatch_source_t ds
, void(^work
)(void)) {
441 GET_ASAN_BLOCK(work
);
442 REAL(dispatch_source_set_event_handler
)(ds
, asan_block
);
446 // The following stuff has been extremely helpful while looking for the
447 // unhandled functions that spawned jobs on Chromium shutdown. If the verbosity
448 // level is 2 or greater, we wrap pthread_workqueue_additem_np() in order to
449 // find the points of worker thread creation (each of such threads may be used
450 // to run several tasks, that's why this is not enough to support the whole
453 void *wrap_workitem_func(void *arg
) {
454 if (flags()->verbosity
>= 2) {
455 Report("wrap_workitem_func: %p, pthread_self: %p\n", arg
, pthread_self());
457 asan_block_context_t
*ctxt
= (asan_block_context_t
*)arg
;
458 worker_t fn
= (worker_t
)(ctxt
->func
);
459 void *result
= fn(ctxt
->block
);
460 GET_STACK_TRACE_HERE(kStackTraceMax
);
461 asan_free(arg
, &stack
);
465 INTERCEPTOR(int, pthread_workqueue_additem_np
, pthread_workqueue_t workq
,
466 void *(*workitem_func
)(void *), void * workitem_arg
,
467 pthread_workitem_handle_t
* itemhandlep
, unsigned int *gencountp
) {
468 GET_STACK_TRACE_HERE(kStackTraceMax
);
469 asan_block_context_t
*asan_ctxt
=
470 (asan_block_context_t
*) asan_malloc(sizeof(asan_block_context_t
), &stack
);
471 asan_ctxt
->block
= workitem_arg
;
472 asan_ctxt
->func
= (dispatch_function_t
)workitem_func
;
473 asan_ctxt
->parent_tid
= asanThreadRegistry().GetCurrentTidOrInvalid();
474 if (flags()->verbosity
>= 2) {
475 Report("pthread_workqueue_additem_np: %p\n", asan_ctxt
);
476 PRINT_CURRENT_STACK();
478 return REAL(pthread_workqueue_additem_np
)(workq
, wrap_workitem_func
,
479 asan_ctxt
, itemhandlep
,
483 // See http://opensource.apple.com/source/CF/CF-635.15/CFString.c
484 int __CFStrIsConstant(CFStringRef str
) {
485 CFRuntimeBase
*base
= (CFRuntimeBase
*)str
;
487 return base
->_rc
== 0;
489 return (base
->_cfinfo
[CF_RC_BITS
]) == 0;
493 INTERCEPTOR(CFStringRef
, CFStringCreateCopy
, CFAllocatorRef alloc
,
495 if (__CFStrIsConstant(str
)) {
498 return REAL(CFStringCreateCopy
)(alloc
, str
);
502 DECLARE_REAL_AND_INTERCEPTOR(void, free
, void *ptr
)
504 DECLARE_REAL_AND_INTERCEPTOR(void, __CFInitialize
, void)
508 void InitializeMacInterceptors() {
509 CHECK(INTERCEPT_FUNCTION(dispatch_async_f
));
510 CHECK(INTERCEPT_FUNCTION(dispatch_sync_f
));
511 CHECK(INTERCEPT_FUNCTION(dispatch_after_f
));
512 CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f
));
513 CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f
));
514 // We don't need to intercept pthread_workqueue_additem_np() to support the
515 // libdispatch API, but it helps us to debug the unsupported functions. Let's
516 // intercept it only during verbose runs.
517 if (flags()->verbosity
>= 2) {
518 CHECK(INTERCEPT_FUNCTION(pthread_workqueue_additem_np
));
520 // Normally CFStringCreateCopy should not copy constant CF strings.
521 // Replacing the default CFAllocator causes constant strings to be copied
522 // rather than just returned, which leads to bugs in big applications like
523 // Chromium and WebKit, see
524 // http://code.google.com/p/address-sanitizer/issues/detail?id=10
525 // Until this problem is fixed we need to check that the string is
526 // non-constant before calling CFStringCreateCopy.
527 CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy
));
528 // Some of the library functions call free() directly, so we have to
530 CHECK(INTERCEPT_FUNCTION(free
));
531 if (flags()->replace_cfallocator
) {
532 CHECK(INTERCEPT_FUNCTION(__CFInitialize
));
536 } // namespace __asan