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