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