13cab2bb3Spatrick //===-- asan_mac.cpp ------------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of AddressSanitizer, an address sanity checker.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Mac-specific details.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick
143cab2bb3Spatrick #include "sanitizer_common/sanitizer_platform.h"
15*810390e3Srobert #if SANITIZER_APPLE
163cab2bb3Spatrick
173cab2bb3Spatrick #include "asan_interceptors.h"
183cab2bb3Spatrick #include "asan_internal.h"
193cab2bb3Spatrick #include "asan_mapping.h"
203cab2bb3Spatrick #include "asan_stack.h"
213cab2bb3Spatrick #include "asan_thread.h"
223cab2bb3Spatrick #include "sanitizer_common/sanitizer_atomic.h"
233cab2bb3Spatrick #include "sanitizer_common/sanitizer_libc.h"
243cab2bb3Spatrick #include "sanitizer_common/sanitizer_mac.h"
253cab2bb3Spatrick
263cab2bb3Spatrick #include <dlfcn.h>
273cab2bb3Spatrick #include <fcntl.h>
283cab2bb3Spatrick #include <libkern/OSAtomic.h>
293cab2bb3Spatrick #include <mach-o/dyld.h>
303cab2bb3Spatrick #include <mach-o/getsect.h>
313cab2bb3Spatrick #include <mach-o/loader.h>
323cab2bb3Spatrick #include <pthread.h>
333cab2bb3Spatrick #include <stdlib.h> // for free()
343cab2bb3Spatrick #include <sys/mman.h>
353cab2bb3Spatrick #include <sys/resource.h>
363cab2bb3Spatrick #include <sys/sysctl.h>
373cab2bb3Spatrick #include <sys/ucontext.h>
383cab2bb3Spatrick #include <unistd.h>
393cab2bb3Spatrick
403cab2bb3Spatrick // from <crt_externs.h>, but we don't have that file on iOS
413cab2bb3Spatrick extern "C" {
423cab2bb3Spatrick extern char ***_NSGetArgv(void);
433cab2bb3Spatrick extern char ***_NSGetEnviron(void);
443cab2bb3Spatrick }
453cab2bb3Spatrick
463cab2bb3Spatrick namespace __asan {
473cab2bb3Spatrick
InitializePlatformInterceptors()483cab2bb3Spatrick void InitializePlatformInterceptors() {}
InitializePlatformExceptionHandlers()493cab2bb3Spatrick void InitializePlatformExceptionHandlers() {}
IsSystemHeapAddress(uptr addr)503cab2bb3Spatrick bool IsSystemHeapAddress (uptr addr) { return false; }
513cab2bb3Spatrick
523cab2bb3Spatrick // No-op. Mac does not support static linkage anyway.
AsanDoesNotSupportStaticLinkage()533cab2bb3Spatrick void *AsanDoesNotSupportStaticLinkage() {
543cab2bb3Spatrick return 0;
553cab2bb3Spatrick }
563cab2bb3Spatrick
FindDynamicShadowStart()573cab2bb3Spatrick uptr FindDynamicShadowStart() {
58*810390e3Srobert return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE,
59d89ec533Spatrick /*min_shadow_base_alignment*/ 0, kHighMemEnd);
603cab2bb3Spatrick }
613cab2bb3Spatrick
623cab2bb3Spatrick // No-op. Mac does not support static linkage anyway.
AsanCheckDynamicRTPrereqs()633cab2bb3Spatrick void AsanCheckDynamicRTPrereqs() {}
643cab2bb3Spatrick
653cab2bb3Spatrick // No-op. Mac does not support static linkage anyway.
AsanCheckIncompatibleRT()663cab2bb3Spatrick void AsanCheckIncompatibleRT() {}
673cab2bb3Spatrick
AsanApplyToGlobals(globals_op_fptr op,const void * needle)683cab2bb3Spatrick void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
693cab2bb3Spatrick // Find the Mach-O header for the image containing the needle
703cab2bb3Spatrick Dl_info info;
713cab2bb3Spatrick int err = dladdr(needle, &info);
723cab2bb3Spatrick if (err == 0) return;
733cab2bb3Spatrick
743cab2bb3Spatrick #if __LP64__
753cab2bb3Spatrick const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase;
763cab2bb3Spatrick #else
773cab2bb3Spatrick const struct mach_header *mh = (struct mach_header *)info.dli_fbase;
783cab2bb3Spatrick #endif
793cab2bb3Spatrick
803cab2bb3Spatrick // Look up the __asan_globals section in that image and register its globals
813cab2bb3Spatrick unsigned long size = 0;
823cab2bb3Spatrick __asan_global *globals = (__asan_global *)getsectiondata(
833cab2bb3Spatrick mh,
843cab2bb3Spatrick "__DATA", "__asan_globals",
853cab2bb3Spatrick &size);
863cab2bb3Spatrick
873cab2bb3Spatrick if (!globals) return;
883cab2bb3Spatrick if (size % sizeof(__asan_global) != 0) return;
893cab2bb3Spatrick op(globals, size / sizeof(__asan_global));
903cab2bb3Spatrick }
913cab2bb3Spatrick
FlushUnneededASanShadowMemory(uptr p,uptr size)92d89ec533Spatrick void FlushUnneededASanShadowMemory(uptr p, uptr size) {
93d89ec533Spatrick // Since asan's mapping is compacting, the shadow chunk may be
94d89ec533Spatrick // not page-aligned, so we only flush the page-aligned portion.
95d89ec533Spatrick ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
96d89ec533Spatrick }
97d89ec533Spatrick
983cab2bb3Spatrick // Support for the following functions from libdispatch on Mac OS:
993cab2bb3Spatrick // dispatch_async_f()
1003cab2bb3Spatrick // dispatch_async()
1013cab2bb3Spatrick // dispatch_sync_f()
1023cab2bb3Spatrick // dispatch_sync()
1033cab2bb3Spatrick // dispatch_after_f()
1043cab2bb3Spatrick // dispatch_after()
1053cab2bb3Spatrick // dispatch_group_async_f()
1063cab2bb3Spatrick // dispatch_group_async()
1073cab2bb3Spatrick // TODO(glider): libdispatch API contains other functions that we don't support
1083cab2bb3Spatrick // yet.
1093cab2bb3Spatrick //
1103cab2bb3Spatrick // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
1113cab2bb3Spatrick // they can cause jobs to run on a thread different from the current one.
1123cab2bb3Spatrick // TODO(glider): if so, we need a test for this (otherwise we should remove
1133cab2bb3Spatrick // them).
1143cab2bb3Spatrick //
1153cab2bb3Spatrick // The following functions use dispatch_barrier_async_f() (which isn't a library
1163cab2bb3Spatrick // function but is exported) and are thus supported:
1173cab2bb3Spatrick // dispatch_source_set_cancel_handler_f()
1183cab2bb3Spatrick // dispatch_source_set_cancel_handler()
1193cab2bb3Spatrick // dispatch_source_set_event_handler_f()
1203cab2bb3Spatrick // dispatch_source_set_event_handler()
1213cab2bb3Spatrick //
1223cab2bb3Spatrick // The reference manual for Grand Central Dispatch is available at
1233cab2bb3Spatrick // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
1243cab2bb3Spatrick // The implementation details are at
1253cab2bb3Spatrick // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
1263cab2bb3Spatrick
1273cab2bb3Spatrick typedef void* dispatch_group_t;
1283cab2bb3Spatrick typedef void* dispatch_queue_t;
1293cab2bb3Spatrick typedef void* dispatch_source_t;
1303cab2bb3Spatrick typedef u64 dispatch_time_t;
1313cab2bb3Spatrick typedef void (*dispatch_function_t)(void *block);
1323cab2bb3Spatrick typedef void* (*worker_t)(void *block);
1333cab2bb3Spatrick
1343cab2bb3Spatrick // A wrapper for the ObjC blocks used to support libdispatch.
1353cab2bb3Spatrick typedef struct {
1363cab2bb3Spatrick void *block;
1373cab2bb3Spatrick dispatch_function_t func;
1383cab2bb3Spatrick u32 parent_tid;
1393cab2bb3Spatrick } asan_block_context_t;
1403cab2bb3Spatrick
1413cab2bb3Spatrick ALWAYS_INLINE
asan_register_worker_thread(int parent_tid,StackTrace * stack)1423cab2bb3Spatrick void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
1433cab2bb3Spatrick AsanThread *t = GetCurrentThread();
1443cab2bb3Spatrick if (!t) {
1453cab2bb3Spatrick t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
1463cab2bb3Spatrick parent_tid, stack, /* detached */ true);
1473cab2bb3Spatrick t->Init();
1483cab2bb3Spatrick asanThreadRegistry().StartThread(t->tid(), GetTid(), ThreadType::Worker,
1493cab2bb3Spatrick nullptr);
1503cab2bb3Spatrick SetCurrentThread(t);
1513cab2bb3Spatrick }
1523cab2bb3Spatrick }
1533cab2bb3Spatrick
1543cab2bb3Spatrick // For use by only those functions that allocated the context via
1553cab2bb3Spatrick // alloc_asan_context().
1563cab2bb3Spatrick extern "C"
asan_dispatch_call_block_and_release(void * block)1573cab2bb3Spatrick void asan_dispatch_call_block_and_release(void *block) {
1583cab2bb3Spatrick GET_STACK_TRACE_THREAD;
1593cab2bb3Spatrick asan_block_context_t *context = (asan_block_context_t*)block;
1603cab2bb3Spatrick VReport(2,
1613cab2bb3Spatrick "asan_dispatch_call_block_and_release(): "
1623cab2bb3Spatrick "context: %p, pthread_self: %p\n",
1633cab2bb3Spatrick block, pthread_self());
1643cab2bb3Spatrick asan_register_worker_thread(context->parent_tid, &stack);
1653cab2bb3Spatrick // Call the original dispatcher for the block.
1663cab2bb3Spatrick context->func(context->block);
1673cab2bb3Spatrick asan_free(context, &stack, FROM_MALLOC);
1683cab2bb3Spatrick }
1693cab2bb3Spatrick
1703cab2bb3Spatrick } // namespace __asan
1713cab2bb3Spatrick
1723cab2bb3Spatrick using namespace __asan;
1733cab2bb3Spatrick
1743cab2bb3Spatrick // Wrap |ctxt| and |func| into an asan_block_context_t.
1753cab2bb3Spatrick // The caller retains control of the allocated context.
1763cab2bb3Spatrick extern "C"
alloc_asan_context(void * ctxt,dispatch_function_t func,BufferedStackTrace * stack)1773cab2bb3Spatrick asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
1783cab2bb3Spatrick BufferedStackTrace *stack) {
1793cab2bb3Spatrick asan_block_context_t *asan_ctxt =
1803cab2bb3Spatrick (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
1813cab2bb3Spatrick asan_ctxt->block = ctxt;
1823cab2bb3Spatrick asan_ctxt->func = func;
1833cab2bb3Spatrick asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
1843cab2bb3Spatrick return asan_ctxt;
1853cab2bb3Spatrick }
1863cab2bb3Spatrick
1873cab2bb3Spatrick // Define interceptor for dispatch_*_f function with the three most common
1883cab2bb3Spatrick // parameters: dispatch_queue_t, context, dispatch_function_t.
1893cab2bb3Spatrick #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
1903cab2bb3Spatrick INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
1913cab2bb3Spatrick dispatch_function_t func) { \
1923cab2bb3Spatrick GET_STACK_TRACE_THREAD; \
1933cab2bb3Spatrick asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
1943cab2bb3Spatrick if (Verbosity() >= 2) { \
1953cab2bb3Spatrick Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
1963cab2bb3Spatrick asan_ctxt, pthread_self()); \
1973cab2bb3Spatrick PRINT_CURRENT_STACK(); \
1983cab2bb3Spatrick } \
1993cab2bb3Spatrick return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
2003cab2bb3Spatrick asan_dispatch_call_block_and_release); \
2013cab2bb3Spatrick }
2023cab2bb3Spatrick
2033cab2bb3Spatrick INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)2043cab2bb3Spatrick INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
2053cab2bb3Spatrick INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
2063cab2bb3Spatrick
2073cab2bb3Spatrick INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
2083cab2bb3Spatrick dispatch_queue_t dq, void *ctxt,
2093cab2bb3Spatrick dispatch_function_t func) {
2103cab2bb3Spatrick GET_STACK_TRACE_THREAD;
2113cab2bb3Spatrick asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
2123cab2bb3Spatrick if (Verbosity() >= 2) {
2133cab2bb3Spatrick Report("dispatch_after_f: %p\n", asan_ctxt);
2143cab2bb3Spatrick PRINT_CURRENT_STACK();
2153cab2bb3Spatrick }
2163cab2bb3Spatrick return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
2173cab2bb3Spatrick asan_dispatch_call_block_and_release);
2183cab2bb3Spatrick }
2193cab2bb3Spatrick
INTERCEPTOR(void,dispatch_group_async_f,dispatch_group_t group,dispatch_queue_t dq,void * ctxt,dispatch_function_t func)2203cab2bb3Spatrick INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
2213cab2bb3Spatrick dispatch_queue_t dq, void *ctxt,
2223cab2bb3Spatrick dispatch_function_t func) {
2233cab2bb3Spatrick GET_STACK_TRACE_THREAD;
2243cab2bb3Spatrick asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
2253cab2bb3Spatrick if (Verbosity() >= 2) {
2263cab2bb3Spatrick Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
2273cab2bb3Spatrick asan_ctxt, pthread_self());
2283cab2bb3Spatrick PRINT_CURRENT_STACK();
2293cab2bb3Spatrick }
2303cab2bb3Spatrick REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
2313cab2bb3Spatrick asan_dispatch_call_block_and_release);
2323cab2bb3Spatrick }
2333cab2bb3Spatrick
2343cab2bb3Spatrick #if !defined(MISSING_BLOCKS_SUPPORT)
2353cab2bb3Spatrick extern "C" {
2363cab2bb3Spatrick void dispatch_async(dispatch_queue_t dq, void(^work)(void));
2373cab2bb3Spatrick void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
2383cab2bb3Spatrick void(^work)(void));
2393cab2bb3Spatrick void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
2403cab2bb3Spatrick void(^work)(void));
2413cab2bb3Spatrick void dispatch_source_set_cancel_handler(dispatch_source_t ds,
2423cab2bb3Spatrick void(^work)(void));
2433cab2bb3Spatrick void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
2443cab2bb3Spatrick }
2453cab2bb3Spatrick
2463cab2bb3Spatrick #define GET_ASAN_BLOCK(work) \
2473cab2bb3Spatrick void (^asan_block)(void); \
2483cab2bb3Spatrick int parent_tid = GetCurrentTidOrInvalid(); \
2493cab2bb3Spatrick asan_block = ^(void) { \
2503cab2bb3Spatrick GET_STACK_TRACE_THREAD; \
2513cab2bb3Spatrick asan_register_worker_thread(parent_tid, &stack); \
2523cab2bb3Spatrick work(); \
2533cab2bb3Spatrick }
2543cab2bb3Spatrick
2553cab2bb3Spatrick INTERCEPTOR(void, dispatch_async,
2563cab2bb3Spatrick dispatch_queue_t dq, void(^work)(void)) {
2573cab2bb3Spatrick ENABLE_FRAME_POINTER;
2583cab2bb3Spatrick GET_ASAN_BLOCK(work);
2593cab2bb3Spatrick REAL(dispatch_async)(dq, asan_block);
2603cab2bb3Spatrick }
2613cab2bb3Spatrick
2623cab2bb3Spatrick INTERCEPTOR(void, dispatch_group_async,
2633cab2bb3Spatrick dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
2643cab2bb3Spatrick ENABLE_FRAME_POINTER;
2653cab2bb3Spatrick GET_ASAN_BLOCK(work);
2663cab2bb3Spatrick REAL(dispatch_group_async)(dg, dq, asan_block);
2673cab2bb3Spatrick }
2683cab2bb3Spatrick
2693cab2bb3Spatrick INTERCEPTOR(void, dispatch_after,
2703cab2bb3Spatrick dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
2713cab2bb3Spatrick ENABLE_FRAME_POINTER;
2723cab2bb3Spatrick GET_ASAN_BLOCK(work);
2733cab2bb3Spatrick REAL(dispatch_after)(when, queue, asan_block);
2743cab2bb3Spatrick }
2753cab2bb3Spatrick
2763cab2bb3Spatrick INTERCEPTOR(void, dispatch_source_set_cancel_handler,
2773cab2bb3Spatrick dispatch_source_t ds, void(^work)(void)) {
2783cab2bb3Spatrick if (!work) {
2793cab2bb3Spatrick REAL(dispatch_source_set_cancel_handler)(ds, work);
2803cab2bb3Spatrick return;
2813cab2bb3Spatrick }
2823cab2bb3Spatrick ENABLE_FRAME_POINTER;
2833cab2bb3Spatrick GET_ASAN_BLOCK(work);
2843cab2bb3Spatrick REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
2853cab2bb3Spatrick }
2863cab2bb3Spatrick
2873cab2bb3Spatrick INTERCEPTOR(void, dispatch_source_set_event_handler,
2883cab2bb3Spatrick dispatch_source_t ds, void(^work)(void)) {
2893cab2bb3Spatrick ENABLE_FRAME_POINTER;
2903cab2bb3Spatrick GET_ASAN_BLOCK(work);
2913cab2bb3Spatrick REAL(dispatch_source_set_event_handler)(ds, asan_block);
2923cab2bb3Spatrick }
2933cab2bb3Spatrick #endif
2943cab2bb3Spatrick
295*810390e3Srobert #endif // SANITIZER_APPLE
296