Home | History | Annotate | Download | only in sanitizer_common
      1 //===-- sanitizer_mac.cc --------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is shared between various sanitizers' runtime libraries and
     11 // implements OSX-specific functions.
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_platform.h"
     15 #if SANITIZER_MAC
     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_flags.h"
     27 #include "sanitizer_internal_defs.h"
     28 #include "sanitizer_libc.h"
     29 #include "sanitizer_placement_new.h"
     30 #include "sanitizer_platform_limits_posix.h"
     31 #include "sanitizer_procmaps.h"
     32 
     33 #if !SANITIZER_IOS
     34 #include <crt_externs.h>  // for _NSGetEnviron
     35 #else
     36 extern char **environ;
     37 #endif
     38 
     39 #if defined(__has_include) && __has_include(<os/trace.h>)
     40 #define SANITIZER_OS_TRACE 1
     41 #include <os/trace.h>
     42 #else
     43 #define SANITIZER_OS_TRACE 0
     44 #endif
     45 
     46 #if !SANITIZER_IOS
     47 #include <crt_externs.h>  // for _NSGetArgv and _NSGetEnviron
     48 #else
     49 extern "C" {
     50   extern char ***_NSGetArgv(void);
     51 }
     52 #endif
     53 
     54 #include <asl.h>
     55 #include <dlfcn.h>  // for dladdr()
     56 #include <errno.h>
     57 #include <fcntl.h>
     58 #include <libkern/OSAtomic.h>
     59 #include <mach-o/dyld.h>
     60 #include <mach/mach.h>
     61 #include <mach/vm_statistics.h>
     62 #include <pthread.h>
     63 #include <sched.h>
     64 #include <signal.h>
     65 #include <stdlib.h>
     66 #include <sys/mman.h>
     67 #include <sys/resource.h>
     68 #include <sys/stat.h>
     69 #include <sys/sysctl.h>
     70 #include <sys/types.h>
     71 #include <sys/wait.h>
     72 #include <unistd.h>
     73 #include <util.h>
     74 
     75 // from <crt_externs.h>, but we don't have that file on iOS
     76 extern "C" {
     77   extern char ***_NSGetArgv(void);
     78   extern char ***_NSGetEnviron(void);
     79 }
     80 
     81 namespace __sanitizer {
     82 
     83 #include "sanitizer_syscall_generic.inc"
     84 
     85 // Direct syscalls, don't call libmalloc hooks.
     86 extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,
     87                         off_t off);
     88 extern "C" int __munmap(void *, size_t);
     89 
     90 // ---------------------- sanitizer_libc.h
     91 uptr internal_mmap(void *addr, size_t length, int prot, int flags,
     92                    int fd, u64 offset) {
     93   if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL);
     94   return (uptr)__mmap(addr, length, prot, flags, fd, offset);
     95 }
     96 
     97 uptr internal_munmap(void *addr, uptr length) {
     98   return __munmap(addr, length);
     99 }
    100 
    101 int internal_mprotect(void *addr, uptr length, int prot) {
    102   return mprotect(addr, length, prot);
    103 }
    104 
    105 uptr internal_close(fd_t fd) {
    106   return close(fd);
    107 }
    108 
    109 uptr internal_open(const char *filename, int flags) {
    110   return open(filename, flags);
    111 }
    112 
    113 uptr internal_open(const char *filename, int flags, u32 mode) {
    114   return open(filename, flags, mode);
    115 }
    116 
    117 uptr internal_read(fd_t fd, void *buf, uptr count) {
    118   return read(fd, buf, count);
    119 }
    120 
    121 uptr internal_write(fd_t fd, const void *buf, uptr count) {
    122   return write(fd, buf, count);
    123 }
    124 
    125 uptr internal_stat(const char *path, void *buf) {
    126   return stat(path, (struct stat *)buf);
    127 }
    128 
    129 uptr internal_lstat(const char *path, void *buf) {
    130   return lstat(path, (struct stat *)buf);
    131 }
    132 
    133 uptr internal_fstat(fd_t fd, void *buf) {
    134   return fstat(fd, (struct stat *)buf);
    135 }
    136 
    137 uptr internal_filesize(fd_t fd) {
    138   struct stat st;
    139   if (internal_fstat(fd, &st))
    140     return -1;
    141   return (uptr)st.st_size;
    142 }
    143 
    144 uptr internal_dup2(int oldfd, int newfd) {
    145   return dup2(oldfd, newfd);
    146 }
    147 
    148 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
    149   return readlink(path, buf, bufsize);
    150 }
    151 
    152 uptr internal_unlink(const char *path) {
    153   return unlink(path);
    154 }
    155 
    156 uptr internal_sched_yield() {
    157   return sched_yield();
    158 }
    159 
    160 void internal__exit(int exitcode) {
    161   _exit(exitcode);
    162 }
    163 
    164 unsigned int internal_sleep(unsigned int seconds) {
    165   return sleep(seconds);
    166 }
    167 
    168 uptr internal_getpid() {
    169   return getpid();
    170 }
    171 
    172 int internal_sigaction(int signum, const void *act, void *oldact) {
    173   return sigaction(signum,
    174                    (struct sigaction *)act, (struct sigaction *)oldact);
    175 }
    176 
    177 void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }
    178 
    179 uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
    180                           __sanitizer_sigset_t *oldset) {
    181   return sigprocmask(how, set, oldset);
    182 }
    183 
    184 // Doesn't call pthread_atfork() handlers.
    185 extern "C" pid_t __fork(void);
    186 
    187 int internal_fork() {
    188   return __fork();
    189 }
    190 
    191 int internal_forkpty(int *amaster) {
    192   int master, slave;
    193   if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1;
    194   int pid = __fork();
    195   if (pid == -1) {
    196     close(master);
    197     close(slave);
    198     return -1;
    199   }
    200   if (pid == 0) {
    201     close(master);
    202     if (login_tty(slave) != 0) {
    203       // We already forked, there's not much we can do.  Let's quit.
    204       Report("login_tty failed (errno %d)\n", errno);
    205       internal__exit(1);
    206     }
    207   } else {
    208     *amaster = master;
    209     close(slave);
    210   }
    211   return pid;
    212 }
    213 
    214 uptr internal_rename(const char *oldpath, const char *newpath) {
    215   return rename(oldpath, newpath);
    216 }
    217 
    218 uptr internal_ftruncate(fd_t fd, uptr size) {
    219   return ftruncate(fd, size);
    220 }
    221 
    222 uptr internal_execve(const char *filename, char *const argv[],
    223                      char *const envp[]) {
    224   return execve(filename, argv, envp);
    225 }
    226 
    227 uptr internal_waitpid(int pid, int *status, int options) {
    228   return waitpid(pid, status, options);
    229 }
    230 
    231 // ----------------- sanitizer_common.h
    232 bool FileExists(const char *filename) {
    233   struct stat st;
    234   if (stat(filename, &st))
    235     return false;
    236   // Sanity check: filename is a regular file.
    237   return S_ISREG(st.st_mode);
    238 }
    239 
    240 uptr GetTid() {
    241   // FIXME: This can potentially get truncated on 32-bit, where uptr is 4 bytes.
    242   uint64_t tid;
    243   pthread_threadid_np(nullptr, &tid);
    244   return tid;
    245 }
    246 
    247 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
    248                                 uptr *stack_bottom) {
    249   CHECK(stack_top);
    250   CHECK(stack_bottom);
    251   uptr stacksize = pthread_get_stacksize_np(pthread_self());
    252   // pthread_get_stacksize_np() returns an incorrect stack size for the main
    253   // thread on Mavericks. See
    254   // https://github.com/google/sanitizers/issues/261
    255   if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
    256       stacksize == (1 << 19))  {
    257     struct rlimit rl;
    258     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
    259     // Most often rl.rlim_cur will be the desired 8M.
    260     if (rl.rlim_cur < kMaxThreadStackSize) {
    261       stacksize = rl.rlim_cur;
    262     } else {
    263       stacksize = kMaxThreadStackSize;
    264     }
    265   }
    266   void *stackaddr = pthread_get_stackaddr_np(pthread_self());
    267   *stack_top = (uptr)stackaddr;
    268   *stack_bottom = *stack_top - stacksize;
    269 }
    270 
    271 char **GetEnviron() {
    272 #if !SANITIZER_IOS
    273   char ***env_ptr = _NSGetEnviron();
    274   if (!env_ptr) {
    275     Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
    276            "called after libSystem_initializer().\n");
    277     CHECK(env_ptr);
    278   }
    279   char **environ = *env_ptr;
    280 #endif
    281   CHECK(environ);
    282   return environ;
    283 }
    284 
    285 const char *GetEnv(const char *name) {
    286   char **env = GetEnviron();
    287   uptr name_len = internal_strlen(name);
    288   while (*env != 0) {
    289     uptr len = internal_strlen(*env);
    290     if (len > name_len) {
    291       const char *p = *env;
    292       if (!internal_memcmp(p, name, name_len) &&
    293           p[name_len] == '=') {  // Match.
    294         return *env + name_len + 1;  // String starting after =.
    295       }
    296     }
    297     env++;
    298   }
    299   return 0;
    300 }
    301 
    302 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
    303   CHECK_LE(kMaxPathLength, buf_len);
    304 
    305   // On OS X the executable path is saved to the stack by dyld. Reading it
    306   // from there is much faster than calling dladdr, especially for large
    307   // binaries with symbols.
    308   InternalScopedString exe_path(kMaxPathLength);
    309   uint32_t size = exe_path.size();
    310   if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
    311       realpath(exe_path.data(), buf) != 0) {
    312     return internal_strlen(buf);
    313   }
    314   return 0;
    315 }
    316 
    317 uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
    318   return ReadBinaryName(buf, buf_len);
    319 }
    320 
    321 void ReExec() {
    322   UNIMPLEMENTED();
    323 }
    324 
    325 uptr GetPageSize() {
    326   return sysconf(_SC_PAGESIZE);
    327 }
    328 
    329 BlockingMutex::BlockingMutex() {
    330   internal_memset(this, 0, sizeof(*this));
    331 }
    332 
    333 void BlockingMutex::Lock() {
    334   CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
    335   CHECK_EQ(OS_SPINLOCK_INIT, 0);
    336   CHECK_NE(owner_, (uptr)pthread_self());
    337   OSSpinLockLock((OSSpinLock*)&opaque_storage_);
    338   CHECK(!owner_);
    339   owner_ = (uptr)pthread_self();
    340 }
    341 
    342 void BlockingMutex::Unlock() {
    343   CHECK(owner_ == (uptr)pthread_self());
    344   owner_ = 0;
    345   OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
    346 }
    347 
    348 void BlockingMutex::CheckLocked() {
    349   CHECK_EQ((uptr)pthread_self(), owner_);
    350 }
    351 
    352 u64 NanoTime() {
    353   return 0;
    354 }
    355 
    356 uptr GetTlsSize() {
    357   return 0;
    358 }
    359 
    360 void InitTlsSize() {
    361 }
    362 
    363 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
    364                           uptr *tls_addr, uptr *tls_size) {
    365 #ifndef SANITIZER_GO
    366   uptr stack_top, stack_bottom;
    367   GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
    368   *stk_addr = stack_bottom;
    369   *stk_size = stack_top - stack_bottom;
    370   *tls_addr = 0;
    371   *tls_size = 0;
    372 #else
    373   *stk_addr = 0;
    374   *stk_size = 0;
    375   *tls_addr = 0;
    376   *tls_size = 0;
    377 #endif
    378 }
    379 
    380 void ListOfModules::init() {
    381   clear();
    382   MemoryMappingLayout memory_mapping(false);
    383   memory_mapping.DumpListOfModules(&modules_);
    384 }
    385 
    386 bool IsHandledDeadlySignal(int signum) {
    387   if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))
    388     // Handling fatal signals on watchOS and tvOS devices is disallowed.
    389     return false;
    390   return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
    391 }
    392 
    393 MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
    394 
    395 MacosVersion GetMacosVersionInternal() {
    396   int mib[2] = { CTL_KERN, KERN_OSRELEASE };
    397   char version[100];
    398   uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
    399   for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
    400   // Get the version length.
    401   CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
    402   CHECK_LT(len, maxlen);
    403   CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
    404   switch (version[0]) {
    405     case '9': return MACOS_VERSION_LEOPARD;
    406     case '1': {
    407       switch (version[1]) {
    408         case '0': return MACOS_VERSION_SNOW_LEOPARD;
    409         case '1': return MACOS_VERSION_LION;
    410         case '2': return MACOS_VERSION_MOUNTAIN_LION;
    411         case '3': return MACOS_VERSION_MAVERICKS;
    412         case '4': return MACOS_VERSION_YOSEMITE;
    413         default:
    414           if (IsDigit(version[1]))
    415             return MACOS_VERSION_UNKNOWN_NEWER;
    416           else
    417             return MACOS_VERSION_UNKNOWN;
    418       }
    419     }
    420     default: return MACOS_VERSION_UNKNOWN;
    421   }
    422 }
    423 
    424 MacosVersion GetMacosVersion() {
    425   atomic_uint32_t *cache =
    426       reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
    427   MacosVersion result =
    428       static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
    429   if (result == MACOS_VERSION_UNINITIALIZED) {
    430     result = GetMacosVersionInternal();
    431     atomic_store(cache, result, memory_order_release);
    432   }
    433   return result;
    434 }
    435 
    436 uptr GetRSS() {
    437   struct task_basic_info info;
    438   unsigned count = TASK_BASIC_INFO_COUNT;
    439   kern_return_t result =
    440       task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count);
    441   if (UNLIKELY(result != KERN_SUCCESS)) {
    442     Report("Cannot get task info. Error: %d\n", result);
    443     Die();
    444   }
    445   return info.resident_size;
    446 }
    447 
    448 void *internal_start_thread(void(*func)(void *arg), void *arg) {
    449   // Start the thread with signals blocked, otherwise it can steal user signals.
    450   __sanitizer_sigset_t set, old;
    451   internal_sigfillset(&set);
    452   internal_sigprocmask(SIG_SETMASK, &set, &old);
    453   pthread_t th;
    454   pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
    455   internal_sigprocmask(SIG_SETMASK, &old, 0);
    456   return th;
    457 }
    458 
    459 void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
    460 
    461 #ifndef SANITIZER_GO
    462 static BlockingMutex syslog_lock(LINKER_INITIALIZED);
    463 #endif
    464 
    465 void WriteOneLineToSyslog(const char *s) {
    466 #ifndef SANITIZER_GO
    467   syslog_lock.CheckLocked();
    468   asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
    469 #endif
    470 }
    471 
    472 void LogMessageOnPrintf(const char *str) {
    473   // Log all printf output to CrashLog.
    474   if (common_flags()->abort_on_error)
    475     CRAppendCrashLogMessage(str);
    476 }
    477 
    478 void LogFullErrorReport(const char *buffer) {
    479 #ifndef SANITIZER_GO
    480   // Log with os_trace. This will make it into the crash log.
    481 #if SANITIZER_OS_TRACE
    482   if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) {
    483     // os_trace requires the message (format parameter) to be a string literal.
    484     if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
    485                          sizeof("AddressSanitizer") - 1) == 0)
    486       os_trace("Address Sanitizer reported a failure.");
    487     else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
    488                               sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
    489       os_trace("Undefined Behavior Sanitizer reported a failure.");
    490     else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
    491                               sizeof("ThreadSanitizer") - 1) == 0)
    492       os_trace("Thread Sanitizer reported a failure.");
    493     else
    494       os_trace("Sanitizer tool reported a failure.");
    495 
    496     if (common_flags()->log_to_syslog)
    497       os_trace("Consult syslog for more information.");
    498   }
    499 #endif
    500 
    501   // Log to syslog.
    502   // The logging on OS X may call pthread_create so we need the threading
    503   // environment to be fully initialized. Also, this should never be called when
    504   // holding the thread registry lock since that may result in a deadlock. If
    505   // the reporting thread holds the thread registry mutex, and asl_log waits
    506   // for GCD to dispatch a new thread, the process will deadlock, because the
    507   // pthread_create wrapper needs to acquire the lock as well.
    508   BlockingMutexLock l(&syslog_lock);
    509   if (common_flags()->log_to_syslog)
    510     WriteToSyslog(buffer);
    511 
    512   // The report is added to CrashLog as part of logging all of Printf output.
    513 #endif
    514 }
    515 
    516 SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
    517 #if defined(__x86_64__) || defined(__i386__)
    518   ucontext_t *ucontext = static_cast<ucontext_t*>(context);
    519   return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ;
    520 #else
    521   return UNKNOWN;
    522 #endif
    523 }
    524 
    525 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
    526   ucontext_t *ucontext = (ucontext_t*)context;
    527 # if defined(__aarch64__)
    528   *pc = ucontext->uc_mcontext->__ss.__pc;
    529 #   if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
    530   *bp = ucontext->uc_mcontext->__ss.__fp;
    531 #   else
    532   *bp = ucontext->uc_mcontext->__ss.__lr;
    533 #   endif
    534   *sp = ucontext->uc_mcontext->__ss.__sp;
    535 # elif defined(__x86_64__)
    536   *pc = ucontext->uc_mcontext->__ss.__rip;
    537   *bp = ucontext->uc_mcontext->__ss.__rbp;
    538   *sp = ucontext->uc_mcontext->__ss.__rsp;
    539 # elif defined(__arm__)
    540   *pc = ucontext->uc_mcontext->__ss.__pc;
    541   *bp = ucontext->uc_mcontext->__ss.__r[7];
    542   *sp = ucontext->uc_mcontext->__ss.__sp;
    543 # elif defined(__i386__)
    544   *pc = ucontext->uc_mcontext->__ss.__eip;
    545   *bp = ucontext->uc_mcontext->__ss.__ebp;
    546   *sp = ucontext->uc_mcontext->__ss.__esp;
    547 # else
    548 # error "Unknown architecture"
    549 # endif
    550 }
    551 
    552 #ifndef SANITIZER_GO
    553 static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
    554 LowLevelAllocator allocator_for_env;
    555 
    556 // Change the value of the env var |name|, leaking the original value.
    557 // If |name_value| is NULL, the variable is deleted from the environment,
    558 // otherwise the corresponding "NAME=value" string is replaced with
    559 // |name_value|.
    560 void LeakyResetEnv(const char *name, const char *name_value) {
    561   char **env = GetEnviron();
    562   uptr name_len = internal_strlen(name);
    563   while (*env != 0) {
    564     uptr len = internal_strlen(*env);
    565     if (len > name_len) {
    566       const char *p = *env;
    567       if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
    568         // Match.
    569         if (name_value) {
    570           // Replace the old value with the new one.
    571           *env = const_cast<char*>(name_value);
    572         } else {
    573           // Shift the subsequent pointers back.
    574           char **del = env;
    575           do {
    576             del[0] = del[1];
    577           } while (*del++);
    578         }
    579       }
    580     }
    581     env++;
    582   }
    583 }
    584 
    585 SANITIZER_WEAK_CXX_DEFAULT_IMPL
    586 bool ReexecDisabled() {
    587   return false;
    588 }
    589 
    590 extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber;
    591 static const double kMinDyldVersionWithAutoInterposition = 360.0;
    592 
    593 bool DyldNeedsEnvVariable() {
    594   // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users
    595   // still may want use them on older systems. On older Darwin platforms, dyld
    596   // doesn't export dyldVersionNumber symbol and we simply return true.
    597   if (!&dyldVersionNumber) return true;
    598   // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if
    599   // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via
    600   // GetMacosVersion() doesn't work for the simulator. Let's instead check
    601   // `dyldVersionNumber`, which is exported by dyld, against a known version
    602   // number from the first OS release where this appeared.
    603   return dyldVersionNumber < kMinDyldVersionWithAutoInterposition;
    604 }
    605 
    606 void MaybeReexec() {
    607   if (ReexecDisabled()) return;
    608 
    609   // Make sure the dynamic runtime library is preloaded so that the
    610   // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
    611   // ourselves.
    612   Dl_info info;
    613   RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info));
    614   char *dyld_insert_libraries =
    615       const_cast<char*>(GetEnv(kDyldInsertLibraries));
    616   uptr old_env_len = dyld_insert_libraries ?
    617       internal_strlen(dyld_insert_libraries) : 0;
    618   uptr fname_len = internal_strlen(info.dli_fname);
    619   const char *dylib_name = StripModuleName(info.dli_fname);
    620   uptr dylib_name_len = internal_strlen(dylib_name);
    621 
    622   bool lib_is_in_env = dyld_insert_libraries &&
    623                        internal_strstr(dyld_insert_libraries, dylib_name);
    624   if (DyldNeedsEnvVariable() && !lib_is_in_env) {
    625     // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
    626     // library.
    627     InternalScopedString program_name(1024);
    628     uint32_t buf_size = program_name.size();
    629     _NSGetExecutablePath(program_name.data(), &buf_size);
    630     char *new_env = const_cast<char*>(info.dli_fname);
    631     if (dyld_insert_libraries) {
    632       // Append the runtime dylib name to the existing value of
    633       // DYLD_INSERT_LIBRARIES.
    634       new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
    635       internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
    636       new_env[old_env_len] = ':';
    637       // Copy fname_len and add a trailing zero.
    638       internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
    639                        fname_len + 1);
    640       // Ok to use setenv() since the wrappers don't depend on the value of
    641       // asan_inited.
    642       setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
    643     } else {
    644       // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
    645       setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
    646     }
    647     VReport(1, "exec()-ing the program with\n");
    648     VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
    649     VReport(1, "to enable wrappers.\n");
    650     execv(program_name.data(), *_NSGetArgv());
    651 
    652     // We get here only if execv() failed.
    653     Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
    654            "which is required for the sanitizer to work. We tried to set the "
    655            "environment variable and re-execute itself, but execv() failed, "
    656            "possibly because of sandbox restrictions. Make sure to launch the "
    657            "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
    658     RAW_CHECK("execv failed" && 0);
    659   }
    660 
    661   // Verify that interceptors really work.  We'll use dlsym to locate
    662   // "pthread_create", if interceptors are working, it should really point to
    663   // "wrap_pthread_create" within our own dylib.
    664   Dl_info info_pthread_create;
    665   void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create");
    666   RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create));
    667   if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) {
    668     Report(
    669         "ERROR: Interceptors are not working. This may be because %s is "
    670         "loaded too late (e.g. via dlopen). Please launch the executable "
    671         "with:\n%s=%s\n",
    672         SanitizerToolName, kDyldInsertLibraries, info.dli_fname);
    673     RAW_CHECK("interceptors not installed" && 0);
    674   }
    675 
    676   if (!lib_is_in_env)
    677     return;
    678 
    679   // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
    680   // the dylib from the environment variable, because interceptors are installed
    681   // and we don't want our children to inherit the variable.
    682 
    683   uptr env_name_len = internal_strlen(kDyldInsertLibraries);
    684   // Allocate memory to hold the previous env var name, its value, the '='
    685   // sign and the '\0' char.
    686   char *new_env = (char*)allocator_for_env.Allocate(
    687       old_env_len + 2 + env_name_len);
    688   RAW_CHECK(new_env);
    689   internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
    690   internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
    691   new_env[env_name_len] = '=';
    692   char *new_env_pos = new_env + env_name_len + 1;
    693 
    694   // Iterate over colon-separated pieces of |dyld_insert_libraries|.
    695   char *piece_start = dyld_insert_libraries;
    696   char *piece_end = NULL;
    697   char *old_env_end = dyld_insert_libraries + old_env_len;
    698   do {
    699     if (piece_start[0] == ':') piece_start++;
    700     piece_end = internal_strchr(piece_start, ':');
    701     if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
    702     if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
    703     uptr piece_len = piece_end - piece_start;
    704 
    705     char *filename_start =
    706         (char *)internal_memrchr(piece_start, '/', piece_len);
    707     uptr filename_len = piece_len;
    708     if (filename_start) {
    709       filename_start += 1;
    710       filename_len = piece_len - (filename_start - piece_start);
    711     } else {
    712       filename_start = piece_start;
    713     }
    714 
    715     // If the current piece isn't the runtime library name,
    716     // append it to new_env.
    717     if ((dylib_name_len != filename_len) ||
    718         (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
    719       if (new_env_pos != new_env + env_name_len + 1) {
    720         new_env_pos[0] = ':';
    721         new_env_pos++;
    722       }
    723       internal_strncpy(new_env_pos, piece_start, piece_len);
    724       new_env_pos += piece_len;
    725     }
    726     // Move on to the next piece.
    727     piece_start = piece_end;
    728   } while (piece_start < old_env_end);
    729 
    730   // Can't use setenv() here, because it requires the allocator to be
    731   // initialized.
    732   // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
    733   // a separate function called after InitializeAllocator().
    734   if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
    735   LeakyResetEnv(kDyldInsertLibraries, new_env);
    736 }
    737 #endif  // SANITIZER_GO
    738 
    739 char **GetArgv() {
    740   return *_NSGetArgv();
    741 }
    742 
    743 }  // namespace __sanitizer
    744 
    745 #endif  // SANITIZER_MAC
    746