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