1 //===-- sanitizer_mac.cc --------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between various sanitizers' runtime libraries and
9 // implements OSX-specific functions.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_platform.h"
15 // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
16 // the clients will most certainly use 64-bit ones as well.
17 #ifndef _DARWIN_USE_64_BIT_INODE
18 #define _DARWIN_USE_64_BIT_INODE 1
22 #include "sanitizer_common.h"
23 #include "sanitizer_flags.h"
24 #include "sanitizer_internal_defs.h"
25 #include "sanitizer_libc.h"
26 #include "sanitizer_mac.h"
27 #include "sanitizer_placement_new.h"
28 #include "sanitizer_platform_limits_posix.h"
29 #include "sanitizer_procmaps.h"
32 #include <crt_externs.h> // for _NSGetEnviron
34 extern char **environ
;
39 #include <libkern/OSAtomic.h>
40 #include <mach-o/dyld.h>
41 #include <mach/mach.h>
42 #include <mach/vm_statistics.h>
48 #include <sys/resource.h>
50 #include <sys/sysctl.h>
51 #include <sys/types.h>
54 namespace __sanitizer
{
56 #include "sanitizer_syscall_generic.inc"
58 // ---------------------- sanitizer_libc.h
59 uptr
internal_mmap(void *addr
, size_t length
, int prot
, int flags
,
61 if (fd
== -1) fd
= VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL
);
62 return (uptr
)mmap(addr
, length
, prot
, flags
, fd
, offset
);
65 uptr
internal_munmap(void *addr
, uptr length
) {
66 return munmap(addr
, length
);
69 int internal_mprotect(void *addr
, uptr length
, int prot
) {
70 return mprotect(addr
, length
, prot
);
73 uptr
internal_close(fd_t fd
) {
77 uptr
internal_open(const char *filename
, int flags
) {
78 return open(filename
, flags
);
81 uptr
internal_open(const char *filename
, int flags
, u32 mode
) {
82 return open(filename
, flags
, mode
);
85 uptr
internal_read(fd_t fd
, void *buf
, uptr count
) {
86 return read(fd
, buf
, count
);
89 uptr
internal_write(fd_t fd
, const void *buf
, uptr count
) {
90 return write(fd
, buf
, count
);
93 uptr
internal_stat(const char *path
, void *buf
) {
94 return stat(path
, (struct stat
*)buf
);
97 uptr
internal_lstat(const char *path
, void *buf
) {
98 return lstat(path
, (struct stat
*)buf
);
101 uptr
internal_fstat(fd_t fd
, void *buf
) {
102 return fstat(fd
, (struct stat
*)buf
);
105 uptr
internal_filesize(fd_t fd
) {
107 if (internal_fstat(fd
, &st
))
109 return (uptr
)st
.st_size
;
112 uptr
internal_dup2(int oldfd
, int newfd
) {
113 return dup2(oldfd
, newfd
);
116 uptr
internal_readlink(const char *path
, char *buf
, uptr bufsize
) {
117 return readlink(path
, buf
, bufsize
);
120 uptr
internal_unlink(const char *path
) {
124 uptr
internal_sched_yield() {
125 return sched_yield();
128 void internal__exit(int exitcode
) {
132 uptr
internal_getpid() {
136 int internal_sigaction(int signum
, const void *act
, void *oldact
) {
137 return sigaction(signum
,
138 (struct sigaction
*)act
, (struct sigaction
*)oldact
);
141 void internal_sigfillset(__sanitizer_sigset_t
*set
) { sigfillset(set
); }
143 uptr
internal_sigprocmask(int how
, __sanitizer_sigset_t
*set
,
144 __sanitizer_sigset_t
*oldset
) {
145 return sigprocmask(how
, set
, oldset
);
148 int internal_fork() {
149 // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
153 uptr
internal_rename(const char *oldpath
, const char *newpath
) {
154 return rename(oldpath
, newpath
);
157 uptr
internal_ftruncate(fd_t fd
, uptr size
) {
158 return ftruncate(fd
, size
);
161 // ----------------- sanitizer_common.h
162 bool FileExists(const char *filename
) {
164 if (stat(filename
, &st
))
166 // Sanity check: filename is a regular file.
167 return S_ISREG(st
.st_mode
);
171 return reinterpret_cast<uptr
>(pthread_self());
174 void GetThreadStackTopAndBottom(bool at_initialization
, uptr
*stack_top
,
175 uptr
*stack_bottom
) {
178 uptr stacksize
= pthread_get_stacksize_np(pthread_self());
179 // pthread_get_stacksize_np() returns an incorrect stack size for the main
180 // thread on Mavericks. See
181 // https://code.google.com/p/address-sanitizer/issues/detail?id=261
182 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS
) && at_initialization
&&
183 stacksize
== (1 << 19)) {
185 CHECK_EQ(getrlimit(RLIMIT_STACK
, &rl
), 0);
186 // Most often rl.rlim_cur will be the desired 8M.
187 if (rl
.rlim_cur
< kMaxThreadStackSize
) {
188 stacksize
= rl
.rlim_cur
;
190 stacksize
= kMaxThreadStackSize
;
193 void *stackaddr
= pthread_get_stackaddr_np(pthread_self());
194 *stack_top
= (uptr
)stackaddr
;
195 *stack_bottom
= *stack_top
- stacksize
;
198 char **GetEnviron() {
200 char ***env_ptr
= _NSGetEnviron();
202 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
203 "called after libSystem_initializer().\n");
206 char **environ
= *env_ptr
;
212 const char *GetEnv(const char *name
) {
213 char **env
= GetEnviron();
214 uptr name_len
= internal_strlen(name
);
216 uptr len
= internal_strlen(*env
);
217 if (len
> name_len
) {
218 const char *p
= *env
;
219 if (!internal_memcmp(p
, name
, name_len
) &&
220 p
[name_len
] == '=') { // Match.
221 return *env
+ name_len
+ 1; // String starting after =.
229 uptr
ReadBinaryName(/*out*/char *buf
, uptr buf_len
) {
230 CHECK_LE(kMaxPathLength
, buf_len
);
232 // On OS X the executable path is saved to the stack by dyld. Reading it
233 // from there is much faster than calling dladdr, especially for large
234 // binaries with symbols.
235 InternalScopedString
exe_path(kMaxPathLength
);
236 uint32_t size
= exe_path
.size();
237 if (_NSGetExecutablePath(exe_path
.data(), &size
) == 0 &&
238 realpath(exe_path
.data(), buf
) != 0) {
239 return internal_strlen(buf
);
244 uptr
ReadLongProcessName(/*out*/char *buf
, uptr buf_len
) {
245 return ReadBinaryName(buf
, buf_len
);
253 return sysconf(_SC_PAGESIZE
);
256 BlockingMutex::BlockingMutex() {
257 internal_memset(this, 0, sizeof(*this));
260 void BlockingMutex::Lock() {
261 CHECK(sizeof(OSSpinLock
) <= sizeof(opaque_storage_
));
262 CHECK_EQ(OS_SPINLOCK_INIT
, 0);
263 CHECK_NE(owner_
, (uptr
)pthread_self());
264 OSSpinLockLock((OSSpinLock
*)&opaque_storage_
);
266 owner_
= (uptr
)pthread_self();
269 void BlockingMutex::Unlock() {
270 CHECK(owner_
== (uptr
)pthread_self());
272 OSSpinLockUnlock((OSSpinLock
*)&opaque_storage_
);
275 void BlockingMutex::CheckLocked() {
276 CHECK_EQ((uptr
)pthread_self(), owner_
);
290 void GetThreadStackAndTls(bool main
, uptr
*stk_addr
, uptr
*stk_size
,
291 uptr
*tls_addr
, uptr
*tls_size
) {
293 uptr stack_top
, stack_bottom
;
294 GetThreadStackTopAndBottom(main
, &stack_top
, &stack_bottom
);
295 *stk_addr
= stack_bottom
;
296 *stk_size
= stack_top
- stack_bottom
;
307 uptr
GetListOfModules(LoadedModule
*modules
, uptr max_modules
,
308 string_predicate_t filter
) {
309 MemoryMappingLayout
memory_mapping(false);
310 return memory_mapping
.DumpListOfModules(modules
, max_modules
, filter
);
313 bool IsDeadlySignal(int signum
) {
314 return (signum
== SIGSEGV
|| signum
== SIGBUS
) && common_flags()->handle_segv
;
317 MacosVersion cached_macos_version
= MACOS_VERSION_UNINITIALIZED
;
319 MacosVersion
GetMacosVersionInternal() {
320 int mib
[2] = { CTL_KERN
, KERN_OSRELEASE
};
322 uptr len
= 0, maxlen
= sizeof(version
) / sizeof(version
[0]);
323 for (uptr i
= 0; i
< maxlen
; i
++) version
[i
] = '\0';
324 // Get the version length.
325 CHECK_NE(sysctl(mib
, 2, 0, &len
, 0, 0), -1);
326 CHECK_LT(len
, maxlen
);
327 CHECK_NE(sysctl(mib
, 2, version
, &len
, 0, 0), -1);
328 switch (version
[0]) {
329 case '9': return MACOS_VERSION_LEOPARD
;
331 switch (version
[1]) {
332 case '0': return MACOS_VERSION_SNOW_LEOPARD
;
333 case '1': return MACOS_VERSION_LION
;
334 case '2': return MACOS_VERSION_MOUNTAIN_LION
;
335 case '3': return MACOS_VERSION_MAVERICKS
;
336 case '4': return MACOS_VERSION_YOSEMITE
;
338 if (IsDigit(version
[1]))
339 return MACOS_VERSION_UNKNOWN_NEWER
;
341 return MACOS_VERSION_UNKNOWN
;
344 default: return MACOS_VERSION_UNKNOWN
;
348 MacosVersion
GetMacosVersion() {
349 atomic_uint32_t
*cache
=
350 reinterpret_cast<atomic_uint32_t
*>(&cached_macos_version
);
351 MacosVersion result
=
352 static_cast<MacosVersion
>(atomic_load(cache
, memory_order_acquire
));
353 if (result
== MACOS_VERSION_UNINITIALIZED
) {
354 result
= GetMacosVersionInternal();
355 atomic_store(cache
, result
, memory_order_release
);
361 struct task_basic_info info
;
362 unsigned count
= TASK_BASIC_INFO_COUNT
;
363 kern_return_t result
=
364 task_info(mach_task_self(), TASK_BASIC_INFO
, (task_info_t
)&info
, &count
);
365 if (UNLIKELY(result
!= KERN_SUCCESS
)) {
366 Report("Cannot get task info. Error: %d\n", result
);
369 return info
.resident_size
;
372 void *internal_start_thread(void(*func
)(void *arg
), void *arg
) {
373 // Start the thread with signals blocked, otherwise it can steal user signals.
374 __sanitizer_sigset_t set
, old
;
375 internal_sigfillset(&set
);
376 internal_sigprocmask(SIG_SETMASK
, &set
, &old
);
378 pthread_create(&th
, 0, (void*(*)(void *arg
))func
, arg
);
379 internal_sigprocmask(SIG_SETMASK
, &old
, 0);
383 void internal_join_thread(void *th
) { pthread_join((pthread_t
)th
, 0); }
385 void GetPcSpBp(void *context
, uptr
*pc
, uptr
*sp
, uptr
*bp
) {
386 ucontext_t
*ucontext
= (ucontext_t
*)context
;
387 # if defined(__aarch64__)
388 *pc
= ucontext
->uc_mcontext
->__ss
.__pc
;
389 # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
390 *bp
= ucontext
->uc_mcontext
->__ss
.__fp
;
392 *bp
= ucontext
->uc_mcontext
->__ss
.__lr
;
394 *sp
= ucontext
->uc_mcontext
->__ss
.__sp
;
395 # elif defined(__x86_64__)
396 *pc
= ucontext
->uc_mcontext
->__ss
.__rip
;
397 *bp
= ucontext
->uc_mcontext
->__ss
.__rbp
;
398 *sp
= ucontext
->uc_mcontext
->__ss
.__rsp
;
399 # elif defined(__arm__)
400 *pc
= ucontext
->uc_mcontext
->__ss
.__pc
;
401 *bp
= ucontext
->uc_mcontext
->__ss
.__r
[7];
402 *sp
= ucontext
->uc_mcontext
->__ss
.__sp
;
403 # elif defined(__i386__)
404 *pc
= ucontext
->uc_mcontext
->__ss
.__eip
;
405 *bp
= ucontext
->uc_mcontext
->__ss
.__ebp
;
406 *sp
= ucontext
->uc_mcontext
->__ss
.__esp
;
408 # error "Unknown architecture"
412 } // namespace __sanitizer
414 #endif // SANITIZER_MAC