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