brintos

brintos / llvm-project-archived public Read only

0
0
Text · 52.1 KiB · a6f7571 Raw
1622 lines · cpp
1//===-- sanitizer_mac.cpp -------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between various sanitizers' runtime libraries and10// implements OSX-specific functions.11//===----------------------------------------------------------------------===//12 13#include "sanitizer_platform.h"14#if SANITIZER_APPLE15#  include "interception/interception.h"16#  include "sanitizer_mac.h"17 18// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so19// the clients will most certainly use 64-bit ones as well.20#  ifndef _DARWIN_USE_64_BIT_INODE21#    define _DARWIN_USE_64_BIT_INODE 122#  endif23#  include <stdio.h>24 25// Start searching for available memory region past PAGEZERO, which is26// 4KB on 32-bit and 4GB on 64-bit.27#  define GAP_SEARCH_START_ADDRESS \28    ((SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000)29 30#  include "sanitizer_common.h"31#  include "sanitizer_file.h"32#  include "sanitizer_flags.h"33#  include "sanitizer_interface_internal.h"34#  include "sanitizer_internal_defs.h"35#  include "sanitizer_libc.h"36#  include "sanitizer_platform_limits_posix.h"37#  include "sanitizer_procmaps.h"38#  include "sanitizer_ptrauth.h"39 40#  if !SANITIZER_IOS41#    include <crt_externs.h>  // for _NSGetEnviron42#  else43extern char **environ;44#  endif45 46// Integrate with CrashReporter library if available47#  if defined(__has_include) && __has_include(<CrashReporterClient.h>)48#    define HAVE_CRASHREPORTERCLIENT_H 149#    include <CrashReporterClient.h>50#  else51#    define HAVE_CRASHREPORTERCLIENT_H 052#  endif53 54#  if !SANITIZER_IOS55#    include <crt_externs.h>  // for _NSGetArgv and _NSGetEnviron56#  else57extern "C" {58extern char ***_NSGetArgv(void);59}60#  endif61 62#  include <asl.h>63#  include <dlfcn.h>  // for dladdr()64#  include <errno.h>65#  include <fcntl.h>66#  include <inttypes.h>67#  include <libkern/OSAtomic.h>68#  include <mach-o/dyld.h>69#  include <mach/mach.h>70#  include <mach/mach_error.h>71#  include <mach/mach_time.h>72#  include <mach/vm_statistics.h>73#  include <malloc/malloc.h>74#  include <os/log.h>75#  include <pthread.h>76#  include <pthread/introspection.h>77#  include <sched.h>78#  include <signal.h>79#  include <spawn.h>80#  include <stdlib.h>81#  include <sys/ioctl.h>82#  include <sys/mman.h>83#  include <sys/resource.h>84#  include <sys/stat.h>85#  include <sys/sysctl.h>86#  include <sys/types.h>87#  include <sys/wait.h>88#  include <unistd.h>89#  include <util.h>90 91// From <crt_externs.h>, but we don't have that file on iOS.92extern "C" {93  extern char ***_NSGetArgv(void);94  extern char ***_NSGetEnviron(void);95}96 97// From <mach/mach_vm.h>, but we don't have that file on iOS.98extern "C" {99  extern kern_return_t mach_vm_region_recurse(100    vm_map_t target_task,101    mach_vm_address_t *address,102    mach_vm_size_t *size,103    natural_t *nesting_depth,104    vm_region_recurse_info_t info,105    mach_msg_type_number_t *infoCnt);106 107  extern const void* _dyld_get_shared_cache_range(size_t* length);108}109 110#  if !SANITIZER_GO111// Weak symbol no-op when TSan is not linked112SANITIZER_WEAK_ATTRIBUTE extern void __tsan_set_in_internal_write_call(113    bool value) {}114#  endif115 116namespace __sanitizer {117 118#include "sanitizer_syscall_generic.inc"119 120// Direct syscalls, don't call libmalloc hooks (but not available on 10.6).121extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,122                        off_t off) SANITIZER_WEAK_ATTRIBUTE;123extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE;124 125// ---------------------- sanitizer_libc.h126 127// From <mach/vm_statistics.h>, but not on older OSs.128#ifndef VM_MEMORY_SANITIZER129#define VM_MEMORY_SANITIZER 99130#endif131 132// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of133// giant memory regions (i.e. shadow memory regions).134#define kXnuFastMmapFd 0x4135static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB136static bool use_xnu_fast_mmap = false;137 138uptr internal_mmap(void *addr, size_t length, int prot, int flags,139                   int fd, u64 offset) {140  if (fd == -1) {141    fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER);142    if (length >= kXnuFastMmapThreshold) {143      if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd;144    }145  }146  if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset);147  return (uptr)mmap(addr, length, prot, flags, fd, offset);148}149 150uptr internal_munmap(void *addr, uptr length) {151  if (&__munmap) return __munmap(addr, length);152  return munmap(addr, length);153}154 155uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,156                     void *new_address) {157  CHECK(false && "internal_mremap is unimplemented on Mac");158  return 0;159}160 161int internal_mprotect(void *addr, uptr length, int prot) {162  return mprotect(addr, length, prot);163}164 165int internal_madvise(uptr addr, uptr length, int advice) {166  return madvise((void *)addr, length, advice);167}168 169uptr internal_close(fd_t fd) {170  return close(fd);171}172 173uptr internal_open(const char *filename, int flags) {174  return open(filename, flags);175}176 177uptr internal_open(const char *filename, int flags, u32 mode) {178  return open(filename, flags, mode);179}180 181uptr internal_read(fd_t fd, void *buf, uptr count) {182  return read(fd, buf, count);183}184 185uptr internal_write(fd_t fd, const void *buf, uptr count) {186#  if SANITIZER_GO187  return write(fd, buf, count);188#  else189  // We need to disable interceptors when writing in TSan190  __tsan_set_in_internal_write_call(true);191  uptr res = write(fd, buf, count);192  __tsan_set_in_internal_write_call(false);193  return res;194#  endif195}196 197uptr internal_stat(const char *path, void *buf) {198  return stat(path, (struct stat *)buf);199}200 201uptr internal_lstat(const char *path, void *buf) {202  return lstat(path, (struct stat *)buf);203}204 205uptr internal_fstat(fd_t fd, void *buf) {206  return fstat(fd, (struct stat *)buf);207}208 209uptr internal_filesize(fd_t fd) {210  struct stat st;211  if (internal_fstat(fd, &st))212    return -1;213  return (uptr)st.st_size;214}215 216uptr internal_dup(int oldfd) {217  return dup(oldfd);218}219 220uptr internal_dup2(int oldfd, int newfd) {221  return dup2(oldfd, newfd);222}223 224uptr internal_readlink(const char *path, char *buf, uptr bufsize) {225  return readlink(path, buf, bufsize);226}227 228uptr internal_unlink(const char *path) {229  return unlink(path);230}231 232uptr internal_sched_yield() {233  return sched_yield();234}235 236void internal__exit(int exitcode) {237  _exit(exitcode);238}239 240void internal_usleep(u64 useconds) { usleep(useconds); }241 242uptr internal_getpid() {243  return getpid();244}245 246int internal_dlinfo(void *handle, int request, void *p) {247  UNIMPLEMENTED();248}249 250int internal_sigaction(int signum, const void *act, void *oldact) {251  return sigaction(signum,252                   (const struct sigaction *)act, (struct sigaction *)oldact);253}254 255void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }256 257uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,258                          __sanitizer_sigset_t *oldset) {259  // Don't use sigprocmask here, because it affects all threads.260  return pthread_sigmask(how, set, oldset);261}262 263// Doesn't call pthread_atfork() handlers (but not available on 10.6).264extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE;265 266int internal_fork() {267  if (&__fork)268    return __fork();269  return fork();270}271 272int internal_sysctl(const int *name, unsigned int namelen, void *oldp,273                    uptr *oldlenp, const void *newp, uptr newlen) {274  return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp,275                const_cast<void *>(newp), (size_t)newlen);276}277 278int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,279                          const void *newp, uptr newlen) {280  return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp),281                      (size_t)newlen);282}283 284static fd_t internal_spawn_impl(const char *argv[], const char *envp[],285                                pid_t *pid) {286  fd_t primary_fd = kInvalidFd;287  fd_t secondary_fd = kInvalidFd;288 289  auto fd_closer = at_scope_exit([&] {290    internal_close(primary_fd);291    internal_close(secondary_fd);292  });293 294  // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool295  // in particular detects when it's talking to a pipe and forgets to flush the296  // output stream after sending a response.297  primary_fd = posix_openpt(O_RDWR);298  if (primary_fd == kInvalidFd)299    return kInvalidFd;300 301  int res = grantpt(primary_fd) || unlockpt(primary_fd);302  if (res != 0) return kInvalidFd;303 304  // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems.305  char secondary_pty_name[128];306  res = ioctl(primary_fd, TIOCPTYGNAME, secondary_pty_name);307  if (res == -1) return kInvalidFd;308 309  secondary_fd = internal_open(secondary_pty_name, O_RDWR);310  if (secondary_fd == kInvalidFd)311    return kInvalidFd;312 313  // File descriptor actions314  posix_spawn_file_actions_t acts;315  res = posix_spawn_file_actions_init(&acts);316  if (res != 0) return kInvalidFd;317 318  auto acts_cleanup = at_scope_exit([&] {319    posix_spawn_file_actions_destroy(&acts);320  });321 322  res = posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDIN_FILENO) ||323        posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDOUT_FILENO) ||324        posix_spawn_file_actions_addclose(&acts, secondary_fd);325  if (res != 0) return kInvalidFd;326 327  // Spawn attributes328  posix_spawnattr_t attrs;329  res = posix_spawnattr_init(&attrs);330  if (res != 0) return kInvalidFd;331 332  auto attrs_cleanup  = at_scope_exit([&] {333    posix_spawnattr_destroy(&attrs);334  });335 336  // In the spawned process, close all file descriptors that are not explicitly337  // described by the file actions object. This is Darwin-specific extension.338  res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT);339  if (res != 0) return kInvalidFd;340 341  // posix_spawn342  char **argv_casted = const_cast<char **>(argv);343  char **envp_casted = const_cast<char **>(envp);344  res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);345  if (res != 0) return kInvalidFd;346 347  // Disable echo in the new terminal, disable CR.348  struct termios termflags;349  tcgetattr(primary_fd, &termflags);350  termflags.c_oflag &= ~ONLCR;351  termflags.c_lflag &= ~ECHO;352  tcsetattr(primary_fd, TCSANOW, &termflags);353 354  // On success, do not close primary_fd on scope exit.355  fd_t fd = primary_fd;356  primary_fd = kInvalidFd;357 358  return fd;359}360 361fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {362  // The client program may close its stdin and/or stdout and/or stderr thus363  // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this364  // case the communication is broken if either the parent or the child tries to365  // close or duplicate these descriptors. We temporarily reserve these366  // descriptors here to prevent this.367  fd_t low_fds[3];368  size_t count = 0;369 370  for (; count < 3; count++) {371    low_fds[count] = posix_openpt(O_RDWR);372    if (low_fds[count] >= STDERR_FILENO)373      break;374  }375 376  fd_t fd = internal_spawn_impl(argv, envp, pid);377 378  for (; count > 0; count--) {379    internal_close(low_fds[count]);380  }381 382  return fd;383}384 385uptr internal_rename(const char *oldpath, const char *newpath) {386  return rename(oldpath, newpath);387}388 389uptr internal_ftruncate(fd_t fd, uptr size) {390  return ftruncate(fd, size);391}392 393uptr internal_execve(const char *filename, char *const argv[],394                     char *const envp[]) {395  return execve(filename, argv, envp);396}397 398uptr internal_waitpid(int pid, int *status, int options) {399  return waitpid(pid, status, options);400}401 402// ----------------- sanitizer_common.h403bool FileExists(const char *filename) {404  if (ShouldMockFailureToOpen(filename))405    return false;406  struct stat st;407  if (stat(filename, &st))408    return false;409  // Sanity check: filename is a regular file.410  return S_ISREG(st.st_mode);411}412 413bool DirExists(const char *path) {414  struct stat st;415  if (stat(path, &st))416    return false;417  return S_ISDIR(st.st_mode);418}419 420ThreadID GetTid() {421  ThreadID tid;422  pthread_threadid_np(nullptr, &tid);423  return tid;424}425 426void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,427                                uptr *stack_bottom) {428  CHECK(stack_top);429  CHECK(stack_bottom);430  uptr stacksize = pthread_get_stacksize_np(pthread_self());431  // pthread_get_stacksize_np() returns an incorrect stack size for the main432  // thread on Mavericks. See433  // https://github.com/google/sanitizers/issues/261434  if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization &&435      stacksize == (1 << 19))  {436    struct rlimit rl;437    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);438    // Most often rl.rlim_cur will be the desired 8M.439    if (rl.rlim_cur < kMaxThreadStackSize) {440      stacksize = rl.rlim_cur;441    } else {442      stacksize = kMaxThreadStackSize;443    }444  }445  void *stackaddr = pthread_get_stackaddr_np(pthread_self());446  *stack_top = (uptr)stackaddr;447  *stack_bottom = *stack_top - stacksize;448}449 450char **GetEnviron() {451#if !SANITIZER_IOS452  char ***env_ptr = _NSGetEnviron();453  if (!env_ptr) {454    Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "455           "called after libSystem_initializer().\n");456    CHECK(env_ptr);457  }458  char **environ = *env_ptr;459#endif460  CHECK(environ);461  return environ;462}463 464const char *GetEnv(const char *name) {465  char **env = GetEnviron();466  uptr name_len = internal_strlen(name);467  while (*env != 0) {468    uptr len = internal_strlen(*env);469    if (len > name_len) {470      const char *p = *env;471      if (!internal_memcmp(p, name, name_len) &&472          p[name_len] == '=') {  // Match.473        return *env + name_len + 1;  // String starting after =.474      }475    }476    env++;477  }478  return 0;479}480 481uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {482  CHECK_LE(kMaxPathLength, buf_len);483 484  // On OS X the executable path is saved to the stack by dyld. Reading it485  // from there is much faster than calling dladdr, especially for large486  // binaries with symbols.487  InternalMmapVector<char> exe_path(kMaxPathLength);488  uint32_t size = exe_path.size();489  if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&490      realpath(exe_path.data(), buf) != 0) {491    return internal_strlen(buf);492  }493  return 0;494}495 496uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {497  return ReadBinaryName(buf, buf_len);498}499 500void ReExec() {501  UNIMPLEMENTED();502}503 504void CheckASLR() {505  // Do nothing506}507 508void CheckMPROTECT() {509  // Do nothing510}511 512uptr GetPageSize() {513  return sysconf(_SC_PAGESIZE);514}515 516extern "C" unsigned malloc_num_zones;517extern "C" malloc_zone_t **malloc_zones;518malloc_zone_t sanitizer_zone;519 520// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If521// libmalloc tries to set up a different zone as malloc_zones[0], it will call522// mprotect(malloc_zones, ..., PROT_READ).  This interceptor will catch that and523// make sure we are still the first (default) zone.524void MprotectMallocZones(void *addr, int prot) {525  if (addr == malloc_zones && prot == PROT_READ) {526    if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) {527      for (unsigned i = 1; i < malloc_num_zones; i++) {528        if (malloc_zones[i] == &sanitizer_zone) {529          // Swap malloc_zones[0] and malloc_zones[i].530          malloc_zones[i] = malloc_zones[0];531          malloc_zones[0] = &sanitizer_zone;532          break;533        }534      }535    }536  }537}538 539void FutexWait(atomic_uint32_t *p, u32 cmp) {540  // FIXME: implement actual blocking.541  sched_yield();542}543 544void FutexWake(atomic_uint32_t *p, u32 count) {}545 546u64 NanoTime() {547  timeval tv;548  internal_memset(&tv, 0, sizeof(tv));549  gettimeofday(&tv, 0);550  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;551}552 553// This needs to be called during initialization to avoid being racy.554u64 MonotonicNanoTime() {555  static mach_timebase_info_data_t timebase_info;556  if (timebase_info.denom == 0) mach_timebase_info(&timebase_info);557  return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom;558}559 560uptr GetTlsSize() {561  return 0;562}563 564uptr TlsBaseAddr() {565  uptr segbase = 0;566#if defined(__x86_64__)567  asm("movq %%gs:0,%0" : "=r"(segbase));568#elif defined(__i386__)569  asm("movl %%gs:0,%0" : "=r"(segbase));570#elif defined(__aarch64__)571  asm("mrs %x0, tpidrro_el0" : "=r"(segbase));572  segbase &= 0x07ul;  // clearing lower bits, cpu id stored there573#endif574  return segbase;575}576 577// The size of the tls on darwin does not appear to be well documented,578// however the vm memory map suggests that it is 1024 uptrs in size,579// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386.580uptr TlsSize() {581#if defined(__x86_64__) || defined(__i386__)582  return 1024 * sizeof(uptr);583#else584  return 0;585#endif586}587 588void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,589                          uptr *tls_begin, uptr *tls_end) {590#  if !SANITIZER_GO591  GetThreadStackTopAndBottom(main, stk_end, stk_begin);592  *tls_begin = TlsBaseAddr();593  *tls_end = *tls_begin + TlsSize();594#  else595  *stk_begin = 0;596  *stk_end = 0;597  *tls_begin = 0;598  *tls_end = 0;599#  endif600}601 602void ListOfModules::init() {603  clearOrInit();604  MemoryMappingLayout memory_mapping(false);605  memory_mapping.DumpListOfModules(&modules_);606}607 608void ListOfModules::fallbackInit() { clear(); }609 610static HandleSignalMode GetHandleSignalModeImpl(int signum) {611  switch (signum) {612    case SIGABRT:613      return common_flags()->handle_abort;614    case SIGILL:615      return common_flags()->handle_sigill;616    case SIGTRAP:617      return common_flags()->handle_sigtrap;618    case SIGFPE:619      return common_flags()->handle_sigfpe;620    case SIGSEGV:621      return common_flags()->handle_segv;622    case SIGBUS:623      return common_flags()->handle_sigbus;624  }625  return kHandleSignalNo;626}627 628HandleSignalMode GetHandleSignalMode(int signum) {629  // Handling fatal signals on watchOS and tvOS devices is disallowed.630  if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))631    return kHandleSignalNo;632  HandleSignalMode result = GetHandleSignalModeImpl(signum);633  if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)634    return kHandleSignalExclusive;635  return result;636}637 638// Offset example:639// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4640constexpr u16 GetOSMajorKernelOffset() {641  if (TARGET_OS_OSX) return 4;642  if (TARGET_OS_IOS || TARGET_OS_TV) return 6;643  if (TARGET_OS_WATCH) return 13;644}645 646using VersStr = char[64];647 648static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {649  u16 kernel_major = GetDarwinKernelVersion().major;650  u16 offset = GetOSMajorKernelOffset();651  CHECK_GE(kernel_major, offset);652  u16 os_major = kernel_major - offset;653 654  const char *format = "%d.0";655  if (TARGET_OS_OSX) {656    if (os_major >= 16) {  // macOS 11+657      os_major -= 5;658    } else {  // macOS 10.15 and below659      format = "10.%d";660    }661  }662  return internal_snprintf(vers, sizeof(VersStr), format, os_major);663}664 665static void GetOSVersion(VersStr vers) {666  uptr len = sizeof(VersStr);667  if (SANITIZER_IOSSIM) {668    const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION");669    if (!vers_env) {670      Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env "671          "var is not set.\n");672      Die();673    }674    len = internal_strlcpy(vers, vers_env, len);675  } else {676    int res =677        internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);678 679    // XNU 17 (macOS 10.13) and below do not provide the sysctl680    // `kern.osproductversion` entry (res != 0).681    bool no_os_version = res != 0;682 683    // For launchd, sanitizer initialization runs before sysctl is setup684    // (res == 0 && len != strlen(vers), vers is not a valid version).  However,685    // the kernel version `kern.osrelease` is available.686    bool launchd = (res == 0 && internal_strlen(vers) < 3);687    if (launchd) CHECK_EQ(internal_getpid(), 1);688 689    if (no_os_version || launchd) {690      len = ApproximateOSVersionViaKernelVersion(vers);691    }692  }693  CHECK_LT(len, sizeof(VersStr));694}695 696void ParseVersion(const char *vers, u16 *major, u16 *minor) {697  // Format: <major>.<minor>[.<patch>]\0698  CHECK_GE(internal_strlen(vers), 3);699  const char *p = vers;700  *major = internal_simple_strtoll(p, &p, /*base=*/10);701  CHECK_EQ(*p, '.');702  p += 1;703  *minor = internal_simple_strtoll(p, &p, /*base=*/10);704}705 706// Aligned versions example:707// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6708static void MapToMacos(u16 *major, u16 *minor) {709  if (TARGET_OS_OSX)710    return;711 712  if (TARGET_OS_IOS || TARGET_OS_TV)713    *major += 2;714  else if (TARGET_OS_WATCH)715    *major += 9;716  else717    UNREACHABLE("unsupported platform");718 719  if (*major >= 16) {  // macOS 11+720    *major -= 5;721  } else {  // macOS 10.15 and below722    *minor = *major;723    *major = 10;724  }725}726 727static MacosVersion GetMacosAlignedVersionInternal() {728  VersStr vers = {};729  GetOSVersion(vers);730 731  u16 major, minor;732  ParseVersion(vers, &major, &minor);733  MapToMacos(&major, &minor);734 735  return MacosVersion(major, minor);736}737 738static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type),739              "MacosVersion cache size");740static atomic_uint32_t cached_macos_version;741 742MacosVersion GetMacosAlignedVersion() {743  atomic_uint32_t::Type result =744      atomic_load(&cached_macos_version, memory_order_acquire);745  if (!result) {746    MacosVersion version = GetMacosAlignedVersionInternal();747    result = *reinterpret_cast<atomic_uint32_t::Type *>(&version);748    atomic_store(&cached_macos_version, result, memory_order_release);749  }750  return *reinterpret_cast<MacosVersion *>(&result);751}752 753DarwinKernelVersion GetDarwinKernelVersion() {754  VersStr vers = {};755  uptr len = sizeof(VersStr);756  int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);757  CHECK_EQ(res, 0);758  CHECK_LT(len, sizeof(VersStr));759 760  u16 major, minor;761  ParseVersion(vers, &major, &minor);762 763  return DarwinKernelVersion(major, minor);764}765 766uptr GetRSS() {767  struct task_basic_info info;768  unsigned count = TASK_BASIC_INFO_COUNT;769  kern_return_t result =770      task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count);771  if (UNLIKELY(result != KERN_SUCCESS)) {772    Report("Cannot get task info. Error: %d\n", result);773    Die();774  }775  return info.resident_size;776}777 778void *internal_start_thread(void *(*func)(void *arg), void *arg) {779  // Start the thread with signals blocked, otherwise it can steal user signals.780  __sanitizer_sigset_t set, old;781  internal_sigfillset(&set);782  internal_sigprocmask(SIG_SETMASK, &set, &old);783  pthread_t th;784  pthread_create(&th, 0, func, arg);785  internal_sigprocmask(SIG_SETMASK, &old, 0);786  return th;787}788 789void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }790 791#if !SANITIZER_GO792static Mutex syslog_lock;793#  endif794 795#  if SANITIZER_DRIVERKIT796#    define SANITIZER_OS_LOG os_log797#  else798#    define SANITIZER_OS_LOG os_log_error799#  endif800 801void WriteOneLineToSyslog(const char *s) {802#if !SANITIZER_GO803  syslog_lock.CheckLocked();804  if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {805    SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s", s);806  } else {807#pragma clang diagnostic push808// as_log is deprecated.809#pragma clang diagnostic ignored "-Wdeprecated-declarations"810    asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);811#pragma clang diagnostic pop812  }813#endif814}815 816// buffer to store crash report application information817static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};818static Mutex crashreporter_info_mutex;819 820extern "C" {821 822#if HAVE_CRASHREPORTERCLIENT_H823// Available in CRASHREPORTER_ANNOTATIONS_VERSION 5+824#    ifdef CRASHREPORTER_ANNOTATIONS_INITIALIZER825CRASHREPORTER_ANNOTATIONS_INITIALIZER()826#    else827// Support for older CrashRerporter annotiations828CRASH_REPORTER_CLIENT_HIDDEN829struct crashreporter_annotations_t gCRAnnotations830    __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {831        CRASHREPORTER_ANNOTATIONS_VERSION,832        0,833        0,834        0,835        0,836        0,837        0,838#      if CRASHREPORTER_ANNOTATIONS_VERSION > 4839        0,840#      endif841};842#    endif843#  else844// Revert to previous crash reporter API if client header is not available845static const char *__crashreporter_info__ __attribute__((__used__)) =846    &crashreporter_info_buff[0];847asm(".desc ___crashreporter_info__, 0x10");848#endif  // HAVE_CRASHREPORTERCLIENT_H849 850}  // extern "C"851 852static void CRAppendCrashLogMessage(const char *msg) {853  Lock l(&crashreporter_info_mutex);854  internal_strlcat(crashreporter_info_buff, msg,855                   sizeof(crashreporter_info_buff));856#if HAVE_CRASHREPORTERCLIENT_H857  (void)CRSetCrashLogMessage(crashreporter_info_buff);858#endif859}860 861void LogMessageOnPrintf(const char *str) {862  // Log all printf output to CrashLog.863  if (common_flags()->abort_on_error)864    CRAppendCrashLogMessage(str);865}866 867void LogFullErrorReport(const char *buffer) {868#  if !SANITIZER_GO869  // When logging with os_log_error this will make it into the crash log.870  if (internal_strncmp(SanitizerToolName, "AddressSanitizer",871                       sizeof("AddressSanitizer") - 1) == 0)872    SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure.");873  else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",874                            sizeof("UndefinedBehaviorSanitizer") - 1) == 0)875    SANITIZER_OS_LOG(OS_LOG_DEFAULT,876                     "Undefined Behavior Sanitizer reported a failure.");877  else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",878                            sizeof("ThreadSanitizer") - 1) == 0)879    SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure.");880  else881    SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure.");882 883  if (common_flags()->log_to_syslog)884    SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information.");885 886  // Log to syslog.887  // The logging on OS X may call pthread_create so we need the threading888  // environment to be fully initialized. Also, this should never be called when889  // holding the thread registry lock since that may result in a deadlock. If890  // the reporting thread holds the thread registry mutex, and asl_log waits891  // for GCD to dispatch a new thread, the process will deadlock, because the892  // pthread_create wrapper needs to acquire the lock as well.893  Lock l(&syslog_lock);894  if (common_flags()->log_to_syslog)895    WriteToSyslog(buffer);896 897  // The report is added to CrashLog as part of logging all of Printf output.898#  endif  // !SANITIZER_GO899}900 901SignalContext::WriteFlag SignalContext::GetWriteFlag() const {902#if defined(__x86_64__) || defined(__i386__)903  ucontext_t *ucontext = static_cast<ucontext_t*>(context);904  return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? Write : Read;905#elif defined(__arm64__)906  ucontext_t *ucontext = static_cast<ucontext_t*>(context);907  return ucontext->uc_mcontext->__es.__esr & 0x40 /*ISS_DA_WNR*/ ? Write : Read;908#else909  return Unknown;910#endif911}912 913bool SignalContext::IsTrueFaultingAddress() const {914  auto si = static_cast<const siginfo_t *>(siginfo);915  // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero.916  return si->si_signo == SIGSEGV && si->si_code != 0;917}918 919#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)920  #define AARCH64_GET_REG(r) \921    (uptr)ptrauth_strip(     \922        (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)923#else924  #define AARCH64_GET_REG(r) (uptr)ucontext->uc_mcontext->__ss.__##r925#endif926 927static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {928  ucontext_t *ucontext = (ucontext_t*)context;929# if defined(__aarch64__)930  *pc = AARCH64_GET_REG(pc);931  *bp = AARCH64_GET_REG(fp);932  *sp = AARCH64_GET_REG(sp);933# elif defined(__x86_64__)934  *pc = ucontext->uc_mcontext->__ss.__rip;935  *bp = ucontext->uc_mcontext->__ss.__rbp;936  *sp = ucontext->uc_mcontext->__ss.__rsp;937# elif defined(__arm__)938  *pc = ucontext->uc_mcontext->__ss.__pc;939  *bp = ucontext->uc_mcontext->__ss.__r[7];940  *sp = ucontext->uc_mcontext->__ss.__sp;941# elif defined(__i386__)942  *pc = ucontext->uc_mcontext->__ss.__eip;943  *bp = ucontext->uc_mcontext->__ss.__ebp;944  *sp = ucontext->uc_mcontext->__ss.__esp;945# else946# error "Unknown architecture"947# endif948}949 950void SignalContext::InitPcSpBp() {951  addr = (uptr)ptrauth_strip((void *)addr, 0);952  GetPcSpBp(context, &pc, &sp, &bp);953}954 955// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers956// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).957static void DisableMmapExcGuardExceptions() {958  using task_exc_guard_behavior_t = uint32_t;959  using task_set_exc_guard_behavior_t =960      kern_return_t(task_t task, task_exc_guard_behavior_t behavior);961  auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym(962      RTLD_DEFAULT, "task_set_exc_guard_behavior");963  if (set_behavior == nullptr) return;964  const task_exc_guard_behavior_t task_exc_guard_none = 0;965  kern_return_t res = set_behavior(mach_task_self(), task_exc_guard_none);966  if (res != KERN_SUCCESS) {967    Report(968        "WARN: task_set_exc_guard_behavior returned %d (%s), "969        "mmap may fail unexpectedly.\n",970        res, mach_error_string(res));971    if (res == KERN_DENIED)972      Report(973          "HINT: Check that task_set_exc_guard_behavior is allowed by "974          "sandbox.\n");975  }976}977 978static void VerifyInterceptorsWorking();979static void StripEnv();980 981void InitializePlatformEarly() {982  // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.983  use_xnu_fast_mmap =984#if defined(__x86_64__)985      GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);986#else987      false;988#endif989  if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0))990    DisableMmapExcGuardExceptions();991 992#  if !SANITIZER_GO993  MonotonicNanoTime();  // Call to initialize mach_timebase_info994  VerifyInterceptorsWorking();995  StripEnv();996#  endif997}998 999#if !SANITIZER_GO1000static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";1001LowLevelAllocator allocator_for_env;1002 1003static bool ShouldCheckInterceptors() {1004  // Restrict "interceptors working?" check1005  const char *sanitizer_names[] = {"AddressSanitizer", "ThreadSanitizer",1006                                   "RealtimeSanitizer"};1007  size_t count = sizeof(sanitizer_names) / sizeof(sanitizer_names[0]);1008  for (size_t i = 0; i < count; i++) {1009    if (internal_strcmp(sanitizer_names[i], SanitizerToolName) == 0)1010      return true;1011  }1012  return false;1013}1014 1015static void VerifyInterceptorsWorking() {1016  if (!common_flags()->verify_interceptors || !ShouldCheckInterceptors())1017    return;1018 1019  // Verify that interceptors really work.  We'll use dlsym to locate1020  // "puts", if interceptors are working, it should really point to1021  // "wrap_puts" within our own dylib.1022  Dl_info info_puts, info_runtime;1023  RAW_CHECK(dladdr(dlsym(RTLD_DEFAULT, "puts"), &info_puts));1024  RAW_CHECK(dladdr((void *)&VerifyInterceptorsWorking, &info_runtime));1025  if (internal_strcmp(info_puts.dli_fname, info_runtime.dli_fname) != 0) {1026    Report(1027        "ERROR: Interceptors are not working. This may be because %s is "1028        "loaded too late (e.g. via dlopen). Please launch the executable "1029        "with:\n%s=%s\n",1030        SanitizerToolName, kDyldInsertLibraries, info_runtime.dli_fname);1031    RAW_CHECK("interceptors not installed" && 0);1032  }1033}1034 1035// Change the value of the env var |name|, leaking the original value.1036// If |name_value| is NULL, the variable is deleted from the environment,1037// otherwise the corresponding "NAME=value" string is replaced with1038// |name_value|.1039static void LeakyResetEnv(const char *name, const char *name_value) {1040  char **env = GetEnviron();1041  uptr name_len = internal_strlen(name);1042  while (*env != 0) {1043    uptr len = internal_strlen(*env);1044    if (len > name_len) {1045      const char *p = *env;1046      if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {1047        // Match.1048        if (name_value) {1049          // Replace the old value with the new one.1050          *env = const_cast<char*>(name_value);1051        } else {1052          // Shift the subsequent pointers back.1053          char **del = env;1054          do {1055            del[0] = del[1];1056          } while (*del++);1057        }1058      }1059    }1060    env++;1061  }1062}1063 1064static void StripEnv() {1065  if (!common_flags()->strip_env)1066    return;1067 1068  char *dyld_insert_libraries =1069      const_cast<char *>(GetEnv(kDyldInsertLibraries));1070  if (!dyld_insert_libraries)1071    return;1072 1073  Dl_info info;1074  RAW_CHECK(dladdr((void *)&StripEnv, &info));1075  const char *dylib_name = StripModuleName(info.dli_fname);1076  bool lib_is_in_env = internal_strstr(dyld_insert_libraries, dylib_name);1077  if (!lib_is_in_env)1078    return;1079 1080  // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove1081  // the dylib from the environment variable, because interceptors are installed1082  // and we don't want our children to inherit the variable.1083 1084  uptr old_env_len = internal_strlen(dyld_insert_libraries);1085  uptr dylib_name_len = internal_strlen(dylib_name);1086  uptr env_name_len = internal_strlen(kDyldInsertLibraries);1087  // Allocate memory to hold the previous env var name, its value, the '='1088  // sign and the '\0' char.1089  char *new_env = (char*)allocator_for_env.Allocate(1090      old_env_len + 2 + env_name_len);1091  RAW_CHECK(new_env);1092  internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);1093  internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);1094  new_env[env_name_len] = '=';1095  char *new_env_pos = new_env + env_name_len + 1;1096 1097  // Iterate over colon-separated pieces of |dyld_insert_libraries|.1098  char *piece_start = dyld_insert_libraries;1099  char *piece_end = NULL;1100  char *old_env_end = dyld_insert_libraries + old_env_len;1101  do {1102    if (piece_start[0] == ':') piece_start++;1103    piece_end = internal_strchr(piece_start, ':');1104    if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;1105    if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;1106    uptr piece_len = piece_end - piece_start;1107 1108    char *filename_start =1109        (char *)internal_memrchr(piece_start, '/', piece_len);1110    uptr filename_len = piece_len;1111    if (filename_start) {1112      filename_start += 1;1113      filename_len = piece_len - (filename_start - piece_start);1114    } else {1115      filename_start = piece_start;1116    }1117 1118    // If the current piece isn't the runtime library name,1119    // append it to new_env.1120    if ((dylib_name_len != filename_len) ||1121        (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {1122      if (new_env_pos != new_env + env_name_len + 1) {1123        new_env_pos[0] = ':';1124        new_env_pos++;1125      }1126      internal_strncpy(new_env_pos, piece_start, piece_len);1127      new_env_pos += piece_len;1128    }1129    // Move on to the next piece.1130    piece_start = piece_end;1131  } while (piece_start < old_env_end);1132 1133  // Can't use setenv() here, because it requires the allocator to be1134  // initialized.1135  // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in1136  // a separate function called after InitializeAllocator().1137  if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;1138  LeakyResetEnv(kDyldInsertLibraries, new_env);1139}1140#endif  // SANITIZER_GO1141 1142// Prints out a consolidated memory map: contiguous regions1143// are merged together.1144static void PrintVmmap() {1145  const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;1146  mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;1147  kern_return_t kr = KERN_SUCCESS;1148 1149  Report("Memory map:\n");1150  mach_vm_address_t last = 0;1151  mach_vm_address_t lastsz = 0;1152 1153  while (1) {1154    mach_vm_size_t vmsize = 0;1155    natural_t depth = 0;1156    vm_region_submap_short_info_data_64_t vminfo;1157    mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;1158    kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,1159                                (vm_region_info_t)&vminfo, &count);1160 1161    if (kr == KERN_DENIED) {1162      Report(1163          "ERROR: mach_vm_region_recurse got KERN_DENIED when printing memory "1164          "map.\n");1165      Report(1166          "HINT: Check whether mach_vm_region_recurse is allowed by "1167          "sandbox.\n");1168    }1169 1170    if (kr == KERN_SUCCESS && address < max_vm_address) {1171      if (last + lastsz == address) {1172        // This region is contiguous with the last; merge together.1173        lastsz += vmsize;1174      } else {1175        if (lastsz)1176          Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last,1177                 (void*)(last + lastsz), lastsz);1178 1179        last = address;1180        lastsz = vmsize;1181      }1182      address += vmsize;1183    } else {1184      // We've reached the end of the memory map. Print the last remaining1185      // region, if there is one.1186      if (lastsz)1187        Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last,1188               (void*)(last + lastsz), lastsz);1189 1190      break;1191    }1192  }1193}1194 1195static void ReportShadowAllocFail(uptr shadow_size_bytes, uptr alignment) {1196  Report(1197      "FATAL: Failed to allocate shadow memory. Tried to allocate %p bytes "1198      "(alignment=%p).\n",1199      (void*)shadow_size_bytes, (void*)alignment);1200  PrintVmmap();1201}1202 1203char **GetArgv() {1204  return *_NSGetArgv();1205}1206 1207#if SANITIZER_IOS && !SANITIZER_IOSSIM1208// The task_vm_info struct is normally provided by the macOS SDK, but we need1209// fields only available in 10.12+. Declare the struct manually to be able to1210// build against older SDKs.1211struct __sanitizer_task_vm_info {1212  mach_vm_size_t virtual_size;1213  integer_t region_count;1214  integer_t page_size;1215  mach_vm_size_t resident_size;1216  mach_vm_size_t resident_size_peak;1217  mach_vm_size_t device;1218  mach_vm_size_t device_peak;1219  mach_vm_size_t internal;1220  mach_vm_size_t internal_peak;1221  mach_vm_size_t external;1222  mach_vm_size_t external_peak;1223  mach_vm_size_t reusable;1224  mach_vm_size_t reusable_peak;1225  mach_vm_size_t purgeable_volatile_pmap;1226  mach_vm_size_t purgeable_volatile_resident;1227  mach_vm_size_t purgeable_volatile_virtual;1228  mach_vm_size_t compressed;1229  mach_vm_size_t compressed_peak;1230  mach_vm_size_t compressed_lifetime;1231  mach_vm_size_t phys_footprint;1232  mach_vm_address_t min_address;1233  mach_vm_address_t max_address;1234};1235#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \1236    (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t)))1237 1238static uptr GetTaskInfoMaxAddress() {1239  __sanitizer_task_vm_info vm_info = {} /* zero initialize */;1240  mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT;1241  int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count);1242  return err ? 0 : vm_info.max_address;1243}1244 1245uptr GetMaxUserVirtualAddress() {1246  static uptr max_vm = GetTaskInfoMaxAddress();1247  if (max_vm != 0) {1248    const uptr ret_value = max_vm - 1;1249    CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);1250    return ret_value;1251  }1252 1253  // xnu cannot provide vm address limit1254# if SANITIZER_WORDSIZE == 321255  constexpr uptr fallback_max_vm = 0xffe00000 - 1;1256# else1257  constexpr uptr fallback_max_vm = 0x200000000 - 1;1258# endif1259  static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,1260                "Max virtual address must be less than mmap range size.");1261  return fallback_max_vm;1262}1263 1264#else // !SANITIZER_IOS1265 1266uptr GetMaxUserVirtualAddress() {1267# if SANITIZER_WORDSIZE == 641268  constexpr uptr max_vm = (1ULL << 47) - 1;  // 0x00007fffffffffffUL;1269# else // SANITIZER_WORDSIZE == 321270  static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");1271  constexpr uptr max_vm = (1ULL << 32) - 1;  // 0xffffffff;1272# endif1273  static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,1274                "Max virtual address must be less than mmap range size.");1275  return max_vm;1276}1277#endif1278 1279uptr GetMaxVirtualAddress() {1280  return GetMaxUserVirtualAddress();1281}1282 1283uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,1284                      uptr min_shadow_base_alignment, uptr &high_mem_end,1285                      uptr granularity) {1286  const uptr alignment =1287      Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);1288  const uptr left_padding =1289      Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);1290 1291  uptr space_size = shadow_size_bytes;1292 1293  uptr largest_gap_found = 0;1294  uptr max_occupied_addr = 0;1295 1296  VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);1297  uptr shadow_start =1298      FindAvailableMemoryRange(space_size, alignment, left_padding,1299                               &largest_gap_found, &max_occupied_addr);1300  // If the shadow doesn't fit, restrict the address space to make it fit.1301  if (shadow_start == 0) {1302    VReport(1303        2,1304        "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n",1305        (void *)largest_gap_found, (void *)max_occupied_addr);1306    uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment);1307    if (new_max_vm < max_occupied_addr) {1308      Report("Unable to find a memory range for dynamic shadow.\n");1309      Report(1310          "\tspace_size = %p\n\tlargest_gap_found = %p\n\tmax_occupied_addr "1311          "= %p\n\tnew_max_vm = %p\n",1312          (void*)space_size, (void*)largest_gap_found, (void*)max_occupied_addr,1313          (void*)new_max_vm);1314      ReportShadowAllocFail(shadow_size_bytes, alignment);1315      CHECK(0 && "cannot place shadow");1316    }1317    RestrictMemoryToMaxAddress(new_max_vm);1318    high_mem_end = new_max_vm - 1;1319    space_size = (high_mem_end >> shadow_scale);1320    VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);1321    shadow_start = FindAvailableMemoryRange(space_size, alignment, left_padding,1322                                            nullptr, nullptr);1323    if (shadow_start == 0) {1324      Report("Unable to find a memory range after restricting VM.\n");1325      ReportShadowAllocFail(shadow_size_bytes, alignment);1326      CHECK(0 && "cannot place shadow after restricting vm");1327    }1328  }1329  CHECK_NE((uptr)0, shadow_start);1330  CHECK(IsAligned(shadow_start, alignment));1331  return shadow_start;1332}1333 1334uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,1335                                uptr num_aliases, uptr ring_buffer_size) {1336  CHECK(false && "HWASan aliasing is unimplemented on Mac");1337  return 0;1338}1339 1340uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,1341                              uptr* largest_gap_found,1342                              uptr* max_occupied_addr) {1343  const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;1344  mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;1345  mach_vm_address_t free_begin = GAP_SEARCH_START_ADDRESS;1346  kern_return_t kr = KERN_SUCCESS;1347  if (largest_gap_found) *largest_gap_found = 0;1348  if (max_occupied_addr) *max_occupied_addr = 0;1349  while (kr == KERN_SUCCESS) {1350    mach_vm_size_t vmsize = 0;1351    natural_t depth = 0;1352    vm_region_submap_short_info_data_64_t vminfo;1353    mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;1354    kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,1355                                (vm_region_info_t)&vminfo, &count);1356 1357    if (kr == KERN_SUCCESS) {1358      // There are cases where going beyond the processes' max vm does1359      // not return KERN_INVALID_ADDRESS so we check for going beyond that1360      // max address as well.1361      if (address > max_vm_address) {1362        address = max_vm_address;1363        kr = -1;  // break after this iteration.1364      }1365 1366      if (max_occupied_addr)1367        *max_occupied_addr = address + vmsize;1368    } else if (kr == KERN_INVALID_ADDRESS) {1369      // No more regions beyond "address", consider the gap at the end of VM.1370      address = max_vm_address;1371 1372      // We will break after this iteration anyway since kr != KERN_SUCCESS1373    } else if (kr == KERN_DENIED) {1374      Report("ERROR: Unable to find a memory range for dynamic shadow.\n");1375      Report("HINT: Ensure mach_vm_region_recurse is allowed under sandbox.\n");1376      Die();1377    } else {1378      Report(1379          "WARNING: mach_vm_region_recurse returned unexpected code %d (%s)\n",1380          kr, mach_error_string(kr));1381      DCHECK(false && "mach_vm_region_recurse returned unexpected code");1382      break;  // address is not valid unless KERN_SUCCESS, therefore we must not1383              // use it.1384    }1385 1386    if (free_begin != address) {1387      // We found a free region [free_begin..address-1].1388      uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);1389      uptr gap_end = RoundDownTo((uptr)Min(address, max_vm_address), alignment);1390      uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0;1391      if (size < gap_size) {1392        return gap_start;1393      }1394 1395      if (largest_gap_found && *largest_gap_found < gap_size) {1396        *largest_gap_found = gap_size;1397      }1398    }1399    // Move to the next region.1400    address += vmsize;1401    free_begin = address;1402  }1403 1404  // We looked at all free regions and could not find one large enough.1405  return 0;1406}1407 1408// This function (when used during initialization when there is1409// only a single thread), can be used to verify that a range1410// of memory hasn't already been mapped, and won't be mapped1411// later in the shared cache.1412//1413// If the syscall mach_vm_region_recurse fails (due to sandbox),1414// we assume that the memory is not mapped so that execution can continue.1415//1416// NOTE: range_end is inclusive1417//1418// WARNING: This function must NOT allocate memory, since it is1419// used in InitializeShadowMemory between where we search for1420// space for shadow and where we actually allocate it.1421bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {1422  mach_vm_size_t vmsize = 0;1423  natural_t depth = 0;1424  vm_region_submap_short_info_data_64_t vminfo;1425  mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;1426  mach_vm_address_t address = range_start;1427 1428  // First, check if the range is already mapped.1429  kern_return_t kr =1430      mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,1431                             (vm_region_info_t)&vminfo, &count);1432 1433  if (kr == KERN_DENIED) {1434    Report(1435        "WARN: mach_vm_region_recurse returned KERN_DENIED when checking "1436        "whether an address is mapped.\n");1437    Report("HINT: Is mach_vm_region_recurse allowed by sandbox?\n");1438  }1439 1440  if (kr == KERN_SUCCESS && !IntervalsAreSeparate(address, address + vmsize - 1,1441                                                  range_start, range_end)) {1442    // Overlaps with already-mapped memory1443    return false;1444  }1445 1446  size_t cacheLength;1447  uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);1448 1449  if (cacheStart &&1450      !IntervalsAreSeparate(cacheStart, cacheStart + cacheLength - 1,1451                            range_start, range_end)) {1452    // Overlaps with shared cache region1453    return false;1454  }1455 1456  // We believe this address is available.1457  return true;1458}1459 1460// FIXME implement on this platform.1461void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}1462 1463void SignalContext::DumpAllRegisters(void *context) {1464  Report("Register values:\n");1465 1466  ucontext_t *ucontext = (ucontext_t*)context;1467# define DUMPREG64(r) \1468    Printf("%s = 0x%016llx  ", #r, ucontext->uc_mcontext->__ss.__ ## r);1469# define DUMPREGA64(r) \1470    Printf("   %s = 0x%016lx  ", #r, AARCH64_GET_REG(r));1471# define DUMPREG32(r) \1472    Printf("%s = 0x%08x  ", #r, ucontext->uc_mcontext->__ss.__ ## r);1473# define DUMPREG_(r)   Printf(" "); DUMPREG(r);1474# define DUMPREG__(r)  Printf("  "); DUMPREG(r);1475# define DUMPREG___(r) Printf("   "); DUMPREG(r);1476 1477# if defined(__x86_64__)1478#  define DUMPREG(r) DUMPREG64(r)1479  DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n");1480  DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n");1481  DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n");1482  DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n");1483# elif defined(__i386__)1484#  define DUMPREG(r) DUMPREG32(r)1485  DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n");1486  DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n");1487# elif defined(__aarch64__)1488#  define DUMPREG(r) DUMPREG64(r)1489  DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n");1490  DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n");1491  DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n");1492  DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n");1493  DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");1494  DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");1495  DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");1496  DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");1497# elif defined(__arm__)1498#  define DUMPREG(r) DUMPREG32(r)1499  DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");1500  DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n");1501  DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n");1502  DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n");1503# else1504# error "Unknown architecture"1505# endif1506 1507# undef DUMPREG641508# undef DUMPREG321509# undef DUMPREG_1510# undef DUMPREG__1511# undef DUMPREG___1512# undef DUMPREG1513}1514 1515static inline bool CompareBaseAddress(const LoadedModule &a,1516                                      const LoadedModule &b) {1517  return a.base_address() < b.base_address();1518}1519 1520void FormatUUID(char *out, uptr size, const u8 *uuid) {1521  internal_snprintf(out, size,1522                    "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-"1523                    "%02X%02X%02X%02X%02X%02X>",1524                    uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],1525                    uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],1526                    uuid[12], uuid[13], uuid[14], uuid[15]);1527}1528 1529void DumpProcessMap() {1530  Printf("Process module map:\n");1531  MemoryMappingLayout memory_mapping(false);1532  InternalMmapVector<LoadedModule> modules;1533  modules.reserve(128);1534  memory_mapping.DumpListOfModules(&modules);1535  Sort(modules.data(), modules.size(), CompareBaseAddress);1536  for (uptr i = 0; i < modules.size(); ++i) {1537    char uuid_str[128];1538    FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());1539    Printf("%p-%p %s (%s) %s\n", (void *)modules[i].base_address(),1540           (void *)modules[i].max_address(), modules[i].full_name(),1541           ModuleArchToString(modules[i].arch()), uuid_str);1542  }1543  Printf("End of module map.\n");1544}1545 1546void CheckNoDeepBind(const char *filename, int flag) {1547  // Do nothing.1548}1549 1550bool GetRandom(void *buffer, uptr length, bool blocking) {1551  if (!buffer || !length || length > 256)1552    return false;1553  // arc4random never fails.1554  REAL(arc4random_buf)(buffer, length);1555  return true;1556}1557 1558u32 GetNumberOfCPUs() {1559  return (u32)sysconf(_SC_NPROCESSORS_ONLN);1560}1561 1562void InitializePlatformCommonFlags(CommonFlags *cf) {}1563 1564// Pthread introspection hook1565//1566// * GCD worker threads are created without a call to pthread_create(), but we1567//   still need to register these threads (with ThreadCreate/Start()).1568// * We use the "pthread introspection hook" below to observe the creation of1569//   such threads.1570// * GCD worker threads don't have parent threads and the CREATE event is1571//   delivered in the context of the thread itself.  CREATE events for regular1572//   threads, are delivered on the parent.  We use this to tell apart which1573//   threads are GCD workers with `thread == pthread_self()`.1574//1575static pthread_introspection_hook_t prev_pthread_introspection_hook;1576static ThreadEventCallbacks thread_event_callbacks;1577 1578static void sanitizer_pthread_introspection_hook(unsigned int event,1579                                                 pthread_t thread, void *addr,1580                                                 size_t size) {1581  // create -> start -> terminate -> destroy1582  // * create/destroy are usually (not guaranteed) delivered on the parent and1583  //   track resource allocation/reclamation1584  // * start/terminate are guaranteed to be delivered in the context of the1585  //   thread and give hooks into "just after (before) thread starts (stops)1586  //   executing"1587  DCHECK(event >= PTHREAD_INTROSPECTION_THREAD_CREATE &&1588         event <= PTHREAD_INTROSPECTION_THREAD_DESTROY);1589 1590  if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {1591    bool gcd_worker = (thread == pthread_self());1592    if (thread_event_callbacks.create)1593      thread_event_callbacks.create((uptr)thread, gcd_worker);1594  } else if (event == PTHREAD_INTROSPECTION_THREAD_START) {1595    CHECK_EQ(thread, pthread_self());1596    if (thread_event_callbacks.start)1597      thread_event_callbacks.start((uptr)thread);1598  }1599 1600  if (prev_pthread_introspection_hook)1601    prev_pthread_introspection_hook(event, thread, addr, size);1602 1603  if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {1604    CHECK_EQ(thread, pthread_self());1605    if (thread_event_callbacks.terminate)1606      thread_event_callbacks.terminate((uptr)thread);1607  } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {1608    if (thread_event_callbacks.destroy)1609      thread_event_callbacks.destroy((uptr)thread);1610  }1611}1612 1613void InstallPthreadIntrospectionHook(const ThreadEventCallbacks &callbacks) {1614  thread_event_callbacks = callbacks;1615  prev_pthread_introspection_hook =1616      pthread_introspection_hook_install(&sanitizer_pthread_introspection_hook);1617}1618 1619}  // namespace __sanitizer1620 1621#endif  // SANITIZER_APPLE1622