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 
17 // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
18 // the clients will most certainly use 64-bit ones as well.
19 #ifndef _DARWIN_USE_64_BIT_INODE
20 #define _DARWIN_USE_64_BIT_INODE 1
21 #endif
22 #include <stdio.h>
23 
24 #include "sanitizer_common.h"
25 #include "sanitizer_flags.h"
26 #include "sanitizer_internal_defs.h"
27 #include "sanitizer_libc.h"
28 #include "sanitizer_mac.h"
29 #include "sanitizer_placement_new.h"
30 #include "sanitizer_procmaps.h"
31 
32 #include <crt_externs.h>  // for _NSGetEnviron
33 #include <fcntl.h>
34 #include <mach-o/dyld.h>
35 #include <pthread.h>
36 #include <sched.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <sys/mman.h>
40 #include <sys/resource.h>
41 #include <sys/stat.h>
42 #include <sys/sysctl.h>
43 #include <sys/types.h>
44 #include <unistd.h>
45 #include <libkern/OSAtomic.h>
46 #include <errno.h>
47 
48 namespace __sanitizer {
49 
50 #include "sanitizer_syscall_generic.inc"
51 
52 // ---------------------- sanitizer_libc.h
internal_mmap(void * addr,size_t length,int prot,int flags,int fd,u64 offset)53 uptr internal_mmap(void *addr, size_t length, int prot, int flags,
54                    int fd, u64 offset) {
55   return (uptr)mmap(addr, length, prot, flags, fd, offset);
56 }
57 
internal_munmap(void * addr,uptr length)58 uptr internal_munmap(void *addr, uptr length) {
59   return munmap(addr, length);
60 }
61 
internal_mprotect(void * addr,uptr length,int prot)62 int internal_mprotect(void *addr, uptr length, int prot) {
63   return mprotect(addr, length, prot);
64 }
65 
internal_close(fd_t fd)66 uptr internal_close(fd_t fd) {
67   return close(fd);
68 }
69 
internal_open(const char * filename,int flags)70 uptr internal_open(const char *filename, int flags) {
71   return open(filename, flags);
72 }
73 
internal_open(const char * filename,int flags,u32 mode)74 uptr internal_open(const char *filename, int flags, u32 mode) {
75   return open(filename, flags, mode);
76 }
77 
internal_read(fd_t fd,void * buf,uptr count)78 uptr internal_read(fd_t fd, void *buf, uptr count) {
79   return read(fd, buf, count);
80 }
81 
internal_write(fd_t fd,const void * buf,uptr count)82 uptr internal_write(fd_t fd, const void *buf, uptr count) {
83   return write(fd, buf, count);
84 }
85 
internal_stat(const char * path,void * buf)86 uptr internal_stat(const char *path, void *buf) {
87   return stat(path, (struct stat *)buf);
88 }
89 
internal_lstat(const char * path,void * buf)90 uptr internal_lstat(const char *path, void *buf) {
91   return lstat(path, (struct stat *)buf);
92 }
93 
internal_fstat(fd_t fd,void * buf)94 uptr internal_fstat(fd_t fd, void *buf) {
95   return fstat(fd, (struct stat *)buf);
96 }
97 
internal_filesize(fd_t fd)98 uptr internal_filesize(fd_t fd) {
99   struct stat st;
100   if (internal_fstat(fd, &st))
101     return -1;
102   return (uptr)st.st_size;
103 }
104 
internal_dup2(int oldfd,int newfd)105 uptr internal_dup2(int oldfd, int newfd) {
106   return dup2(oldfd, newfd);
107 }
108 
internal_readlink(const char * path,char * buf,uptr bufsize)109 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
110   return readlink(path, buf, bufsize);
111 }
112 
internal_unlink(const char * path)113 uptr internal_unlink(const char *path) {
114   return unlink(path);
115 }
116 
internal_sched_yield()117 uptr internal_sched_yield() {
118   return sched_yield();
119 }
120 
internal__exit(int exitcode)121 void internal__exit(int exitcode) {
122   _exit(exitcode);
123 }
124 
internal_getpid()125 uptr internal_getpid() {
126   return getpid();
127 }
128 
internal_sigaction(int signum,const void * act,void * oldact)129 int internal_sigaction(int signum, const void *act, void *oldact) {
130   return sigaction(signum,
131                    (struct sigaction *)act, (struct sigaction *)oldact);
132 }
133 
internal_fork()134 int internal_fork() {
135   // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
136   return fork();
137 }
138 
internal_rename(const char * oldpath,const char * newpath)139 uptr internal_rename(const char *oldpath, const char *newpath) {
140   return rename(oldpath, newpath);
141 }
142 
internal_ftruncate(fd_t fd,uptr size)143 uptr internal_ftruncate(fd_t fd, uptr size) {
144   return ftruncate(fd, size);
145 }
146 
147 // ----------------- sanitizer_common.h
FileExists(const char * filename)148 bool FileExists(const char *filename) {
149   struct stat st;
150   if (stat(filename, &st))
151     return false;
152   // Sanity check: filename is a regular file.
153   return S_ISREG(st.st_mode);
154 }
155 
GetTid()156 uptr GetTid() {
157   return reinterpret_cast<uptr>(pthread_self());
158 }
159 
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)160 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
161                                 uptr *stack_bottom) {
162   CHECK(stack_top);
163   CHECK(stack_bottom);
164   uptr stacksize = pthread_get_stacksize_np(pthread_self());
165   // pthread_get_stacksize_np() returns an incorrect stack size for the main
166   // thread on Mavericks. See
167   // https://code.google.com/p/address-sanitizer/issues/detail?id=261
168   if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
169       stacksize == (1 << 19))  {
170     struct rlimit rl;
171     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
172     // Most often rl.rlim_cur will be the desired 8M.
173     if (rl.rlim_cur < kMaxThreadStackSize) {
174       stacksize = rl.rlim_cur;
175     } else {
176       stacksize = kMaxThreadStackSize;
177     }
178   }
179   void *stackaddr = pthread_get_stackaddr_np(pthread_self());
180   *stack_top = (uptr)stackaddr;
181   *stack_bottom = *stack_top - stacksize;
182 }
183 
GetEnv(const char * name)184 const char *GetEnv(const char *name) {
185   char ***env_ptr = _NSGetEnviron();
186   if (!env_ptr) {
187     Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
188            "called after libSystem_initializer().\n");
189     CHECK(env_ptr);
190   }
191   char **environ = *env_ptr;
192   CHECK(environ);
193   uptr name_len = internal_strlen(name);
194   while (*environ != 0) {
195     uptr len = internal_strlen(*environ);
196     if (len > name_len) {
197       const char *p = *environ;
198       if (!internal_memcmp(p, name, name_len) &&
199           p[name_len] == '=') {  // Match.
200         return *environ + name_len + 1;  // String starting after =.
201       }
202     }
203     environ++;
204   }
205   return 0;
206 }
207 
ReadBinaryName(char * buf,uptr buf_len)208 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
209   CHECK_LE(kMaxPathLength, buf_len);
210 
211   // On OS X the executable path is saved to the stack by dyld. Reading it
212   // from there is much faster than calling dladdr, especially for large
213   // binaries with symbols.
214   InternalScopedString exe_path(kMaxPathLength);
215   uint32_t size = exe_path.size();
216   if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
217       realpath(exe_path.data(), buf) != 0) {
218     return internal_strlen(buf);
219   }
220   return 0;
221 }
222 
ReExec()223 void ReExec() {
224   UNIMPLEMENTED();
225 }
226 
GetPageSize()227 uptr GetPageSize() {
228   return sysconf(_SC_PAGESIZE);
229 }
230 
BlockingMutex()231 BlockingMutex::BlockingMutex() {
232   internal_memset(this, 0, sizeof(*this));
233 }
234 
Lock()235 void BlockingMutex::Lock() {
236   CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
237   CHECK_EQ(OS_SPINLOCK_INIT, 0);
238   CHECK_NE(owner_, (uptr)pthread_self());
239   OSSpinLockLock((OSSpinLock*)&opaque_storage_);
240   CHECK(!owner_);
241   owner_ = (uptr)pthread_self();
242 }
243 
Unlock()244 void BlockingMutex::Unlock() {
245   CHECK(owner_ == (uptr)pthread_self());
246   owner_ = 0;
247   OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
248 }
249 
CheckLocked()250 void BlockingMutex::CheckLocked() {
251   CHECK_EQ((uptr)pthread_self(), owner_);
252 }
253 
NanoTime()254 u64 NanoTime() {
255   return 0;
256 }
257 
GetTlsSize()258 uptr GetTlsSize() {
259   return 0;
260 }
261 
InitTlsSize()262 void InitTlsSize() {
263 }
264 
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)265 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
266                           uptr *tls_addr, uptr *tls_size) {
267 #ifndef SANITIZER_GO
268   uptr stack_top, stack_bottom;
269   GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
270   *stk_addr = stack_bottom;
271   *stk_size = stack_top - stack_bottom;
272   *tls_addr = 0;
273   *tls_size = 0;
274 #else
275   *stk_addr = 0;
276   *stk_size = 0;
277   *tls_addr = 0;
278   *tls_size = 0;
279 #endif
280 }
281 
GetListOfModules(LoadedModule * modules,uptr max_modules,string_predicate_t filter)282 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
283                       string_predicate_t filter) {
284   MemoryMappingLayout memory_mapping(false);
285   return memory_mapping.DumpListOfModules(modules, max_modules, filter);
286 }
287 
IsDeadlySignal(int signum)288 bool IsDeadlySignal(int signum) {
289   return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
290 }
291 
292 MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
293 
GetMacosVersionInternal()294 MacosVersion GetMacosVersionInternal() {
295   int mib[2] = { CTL_KERN, KERN_OSRELEASE };
296   char version[100];
297   uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
298   for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
299   // Get the version length.
300   CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
301   CHECK_LT(len, maxlen);
302   CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
303   switch (version[0]) {
304     case '9': return MACOS_VERSION_LEOPARD;
305     case '1': {
306       switch (version[1]) {
307         case '0': return MACOS_VERSION_SNOW_LEOPARD;
308         case '1': return MACOS_VERSION_LION;
309         case '2': return MACOS_VERSION_MOUNTAIN_LION;
310         case '3': return MACOS_VERSION_MAVERICKS;
311         case '4': return MACOS_VERSION_YOSEMITE;
312         default:
313           if (IsDigit(version[1]))
314             return MACOS_VERSION_UNKNOWN_NEWER;
315           else
316             return MACOS_VERSION_UNKNOWN;
317       }
318     }
319     default: return MACOS_VERSION_UNKNOWN;
320   }
321 }
322 
GetMacosVersion()323 MacosVersion GetMacosVersion() {
324   atomic_uint32_t *cache =
325       reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
326   MacosVersion result =
327       static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
328   if (result == MACOS_VERSION_UNINITIALIZED) {
329     result = GetMacosVersionInternal();
330     atomic_store(cache, result, memory_order_release);
331   }
332   return result;
333 }
334 
GetRSS()335 uptr GetRSS() {
336   return 0;
337 }
338 
internal_start_thread(void (* func)(void * arg),void * arg)339 void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
internal_join_thread(void * th)340 void internal_join_thread(void *th) { }
341 
GetPcSpBp(void * context,uptr * pc,uptr * sp,uptr * bp)342 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
343   ucontext_t *ucontext = (ucontext_t*)context;
344 # if SANITIZER_WORDSIZE == 64
345   *pc = ucontext->uc_mcontext->__ss.__rip;
346   *bp = ucontext->uc_mcontext->__ss.__rbp;
347   *sp = ucontext->uc_mcontext->__ss.__rsp;
348 # else
349   *pc = ucontext->uc_mcontext->__ss.__eip;
350   *bp = ucontext->uc_mcontext->__ss.__ebp;
351   *sp = ucontext->uc_mcontext->__ss.__esp;
352 # endif  // SANITIZER_WORDSIZE
353 }
354 
355 }  // namespace __sanitizer
356 
357 #endif  // SANITIZER_MAC
358