]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
Merge ^/head r308842 through r308867.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / sanitizer_common / sanitizer_mac.cc
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