Path: blob/main/contrib/llvm-project/compiler-rt/lib/asan/asan_mac.cpp
35233 views
//===-- asan_mac.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of AddressSanitizer, an address sanity checker.9//10// Mac-specific details.11//===----------------------------------------------------------------------===//1213#include "sanitizer_common/sanitizer_platform.h"14#if SANITIZER_APPLE1516#include "asan_interceptors.h"17#include "asan_internal.h"18#include "asan_mapping.h"19#include "asan_stack.h"20#include "asan_thread.h"21#include "sanitizer_common/sanitizer_atomic.h"22#include "sanitizer_common/sanitizer_libc.h"23#include "sanitizer_common/sanitizer_mac.h"2425#include <dlfcn.h>26#include <fcntl.h>27#include <libkern/OSAtomic.h>28#include <mach-o/dyld.h>29#include <mach-o/getsect.h>30#include <mach-o/loader.h>31#include <pthread.h>32#include <stdlib.h> // for free()33#include <sys/mman.h>34#include <sys/resource.h>35#include <sys/sysctl.h>36#include <sys/ucontext.h>37#include <unistd.h>3839// from <crt_externs.h>, but we don't have that file on iOS40extern "C" {41extern char ***_NSGetArgv(void);42extern char ***_NSGetEnviron(void);43}4445namespace __asan {4647void InitializePlatformInterceptors() {}48void InitializePlatformExceptionHandlers() {}49bool IsSystemHeapAddress (uptr addr) { return false; }5051uptr FindDynamicShadowStart() {52return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE,53/*min_shadow_base_alignment*/ 0, kHighMemEnd,54GetMmapGranularity());55}5657// No-op. Mac does not support static linkage anyway.58void AsanCheckDynamicRTPrereqs() {}5960// No-op. Mac does not support static linkage anyway.61void AsanCheckIncompatibleRT() {}6263void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {64// Find the Mach-O header for the image containing the needle65Dl_info info;66int err = dladdr(needle, &info);67if (err == 0) return;6869#if __LP64__70const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase;71#else72const struct mach_header *mh = (struct mach_header *)info.dli_fbase;73#endif7475// Look up the __asan_globals section in that image and register its globals76unsigned long size = 0;77__asan_global *globals = (__asan_global *)getsectiondata(78mh,79"__DATA", "__asan_globals",80&size);8182if (!globals) return;83if (size % sizeof(__asan_global) != 0) return;84op(globals, size / sizeof(__asan_global));85}8687void FlushUnneededASanShadowMemory(uptr p, uptr size) {88// Since asan's mapping is compacting, the shadow chunk may be89// not page-aligned, so we only flush the page-aligned portion.90ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));91}9293// Support for the following functions from libdispatch on Mac OS:94// dispatch_async_f()95// dispatch_async()96// dispatch_sync_f()97// dispatch_sync()98// dispatch_after_f()99// dispatch_after()100// dispatch_group_async_f()101// dispatch_group_async()102// TODO(glider): libdispatch API contains other functions that we don't support103// yet.104//105// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are106// they can cause jobs to run on a thread different from the current one.107// TODO(glider): if so, we need a test for this (otherwise we should remove108// them).109//110// The following functions use dispatch_barrier_async_f() (which isn't a library111// function but is exported) and are thus supported:112// dispatch_source_set_cancel_handler_f()113// dispatch_source_set_cancel_handler()114// dispatch_source_set_event_handler_f()115// dispatch_source_set_event_handler()116//117// The reference manual for Grand Central Dispatch is available at118// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html119// The implementation details are at120// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c121122typedef void* dispatch_group_t;123typedef void* dispatch_queue_t;124typedef void* dispatch_source_t;125typedef u64 dispatch_time_t;126typedef void (*dispatch_function_t)(void *block);127typedef void* (*worker_t)(void *block);128typedef unsigned long dispatch_mach_reason;129typedef void *dispatch_mach_msg_t;130typedef int mach_error_t;131typedef void *dispatch_mach_t;132133typedef void (*dispatch_mach_handler_function_t)(void *context,134dispatch_mach_reason reason,135dispatch_mach_msg_t message,136mach_error_t error);137# if !defined(MISSING_BLOCKS_SUPPORT)138typedef void (^dispatch_mach_handler_t)(dispatch_mach_reason reason,139dispatch_mach_msg_t message,140mach_error_t error);141# endif142143// A wrapper for the ObjC blocks used to support libdispatch.144typedef struct {145void *block;146dispatch_function_t func;147u32 parent_tid;148} asan_block_context_t;149150ALWAYS_INLINE151void asan_register_worker_thread(int parent_tid, StackTrace *stack) {152AsanThread *t = GetCurrentThread();153if (!t) {154t = AsanThread::Create(parent_tid, stack, /* detached */ true);155t->Init();156asanThreadRegistry().StartThread(t->tid(), GetTid(), ThreadType::Worker,157nullptr);158SetCurrentThread(t);159}160}161162// For use by only those functions that allocated the context via163// alloc_asan_context().164extern "C"165void asan_dispatch_call_block_and_release(void *block) {166GET_STACK_TRACE_THREAD;167asan_block_context_t *context = (asan_block_context_t*)block;168VReport(2,169"asan_dispatch_call_block_and_release(): "170"context: %p, pthread_self: %p\n",171block, (void*)pthread_self());172asan_register_worker_thread(context->parent_tid, &stack);173// Call the original dispatcher for the block.174context->func(context->block);175asan_free(context, &stack, FROM_MALLOC);176}177178} // namespace __asan179180using namespace __asan;181182// Wrap |ctxt| and |func| into an asan_block_context_t.183// The caller retains control of the allocated context.184extern "C"185asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,186BufferedStackTrace *stack) {187asan_block_context_t *asan_ctxt =188(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);189asan_ctxt->block = ctxt;190asan_ctxt->func = func;191asan_ctxt->parent_tid = GetCurrentTidOrInvalid();192return asan_ctxt;193}194195// Define interceptor for dispatch_*_f function with the three most common196// parameters: dispatch_queue_t, context, dispatch_function_t.197#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \198INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \199dispatch_function_t func) { \200GET_STACK_TRACE_THREAD; \201asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \202if (Verbosity() >= 2) { \203Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \204(void*)asan_ctxt, (void*)pthread_self()); \205PRINT_CURRENT_STACK(); \206} \207return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \208asan_dispatch_call_block_and_release); \209}210211INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)212INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)213INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)214215INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,216dispatch_queue_t dq, void *ctxt,217dispatch_function_t func) {218GET_STACK_TRACE_THREAD;219asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);220if (Verbosity() >= 2) {221Report("dispatch_after_f: %p\n", (void*)asan_ctxt);222PRINT_CURRENT_STACK();223}224return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,225asan_dispatch_call_block_and_release);226}227228INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,229dispatch_queue_t dq, void *ctxt,230dispatch_function_t func) {231GET_STACK_TRACE_THREAD;232asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);233if (Verbosity() >= 2) {234Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",235(void*)asan_ctxt, (void*)pthread_self());236PRINT_CURRENT_STACK();237}238REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,239asan_dispatch_call_block_and_release);240}241242#if !defined(MISSING_BLOCKS_SUPPORT)243extern "C" {244void dispatch_async(dispatch_queue_t dq, void(^work)(void));245void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,246void(^work)(void));247void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,248void(^work)(void));249void dispatch_source_set_cancel_handler(dispatch_source_t ds,250void(^work)(void));251void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));252dispatch_mach_t dispatch_mach_create(const char *label, dispatch_queue_t queue,253dispatch_mach_handler_t handler);254}255256#define GET_ASAN_BLOCK(work) \257void (^asan_block)(void); \258int parent_tid = GetCurrentTidOrInvalid(); \259asan_block = ^(void) { \260GET_STACK_TRACE_THREAD; \261asan_register_worker_thread(parent_tid, &stack); \262work(); \263}264265INTERCEPTOR(void, dispatch_async,266dispatch_queue_t dq, void(^work)(void)) {267ENABLE_FRAME_POINTER;268GET_ASAN_BLOCK(work);269REAL(dispatch_async)(dq, asan_block);270}271272INTERCEPTOR(void, dispatch_group_async,273dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {274ENABLE_FRAME_POINTER;275GET_ASAN_BLOCK(work);276REAL(dispatch_group_async)(dg, dq, asan_block);277}278279INTERCEPTOR(void, dispatch_after,280dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {281ENABLE_FRAME_POINTER;282GET_ASAN_BLOCK(work);283REAL(dispatch_after)(when, queue, asan_block);284}285286INTERCEPTOR(void, dispatch_source_set_cancel_handler,287dispatch_source_t ds, void(^work)(void)) {288if (!work) {289REAL(dispatch_source_set_cancel_handler)(ds, work);290return;291}292ENABLE_FRAME_POINTER;293GET_ASAN_BLOCK(work);294REAL(dispatch_source_set_cancel_handler)(ds, asan_block);295}296297INTERCEPTOR(void, dispatch_source_set_event_handler,298dispatch_source_t ds, void(^work)(void)) {299ENABLE_FRAME_POINTER;300GET_ASAN_BLOCK(work);301REAL(dispatch_source_set_event_handler)(ds, asan_block);302}303304INTERCEPTOR(void *, dispatch_mach_create, const char *label,305dispatch_queue_t dq, dispatch_mach_handler_t handler) {306int parent_tid = GetCurrentTidOrInvalid();307return REAL(dispatch_mach_create)(308label, dq,309^(dispatch_mach_reason reason, dispatch_mach_msg_t message,310mach_error_t error) {311GET_STACK_TRACE_THREAD;312asan_register_worker_thread(parent_tid, &stack);313handler(reason, message, error);314});315}316317INTERCEPTOR(void *, dispatch_mach_create_f, const char *label,318dispatch_queue_t dq, void *ctxt,319dispatch_mach_handler_function_t handler) {320int parent_tid = GetCurrentTidOrInvalid();321return REAL(dispatch_mach_create)(322label, dq,323^(dispatch_mach_reason reason, dispatch_mach_msg_t message,324mach_error_t error) {325GET_STACK_TRACE_THREAD;326asan_register_worker_thread(parent_tid, &stack);327handler(ctxt, reason, message, error);328});329}330331#endif332333#endif // SANITIZER_APPLE334335336