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_procmaps.h"
30 #include <crt_externs.h> // for _NSGetEnviron
36 #include <sys/resource.h>
38 #include <sys/sysctl.h>
39 #include <sys/types.h>
41 #include <libkern/OSAtomic.h>
44 namespace __sanitizer
{
46 #include "sanitizer_syscall_generic.inc"
48 // ---------------------- sanitizer_libc.h
49 uptr
internal_mmap(void *addr
, size_t length
, int prot
, int flags
,
51 return (uptr
)mmap(addr
, length
, prot
, flags
, fd
, offset
);
54 uptr
internal_munmap(void *addr
, uptr length
) {
55 return munmap(addr
, length
);
58 uptr
internal_close(fd_t fd
) {
62 uptr
internal_open(const char *filename
, int flags
) {
63 return open(filename
, flags
);
66 uptr
internal_open(const char *filename
, int flags
, u32 mode
) {
67 return open(filename
, flags
, mode
);
70 uptr
OpenFile(const char *filename
, bool write
) {
71 return internal_open(filename
,
72 write
? O_WRONLY
| O_CREAT
: O_RDONLY
, 0660);
75 uptr
internal_read(fd_t fd
, void *buf
, uptr count
) {
76 return read(fd
, buf
, count
);
79 uptr
internal_write(fd_t fd
, const void *buf
, uptr count
) {
80 return write(fd
, buf
, count
);
83 uptr
internal_stat(const char *path
, void *buf
) {
84 return stat(path
, (struct stat
*)buf
);
87 uptr
internal_lstat(const char *path
, void *buf
) {
88 return lstat(path
, (struct stat
*)buf
);
91 uptr
internal_fstat(fd_t fd
, void *buf
) {
92 return fstat(fd
, (struct stat
*)buf
);
95 uptr
internal_filesize(fd_t fd
) {
97 if (internal_fstat(fd
, &st
))
99 return (uptr
)st
.st_size
;
102 uptr
internal_dup2(int oldfd
, int newfd
) {
103 return dup2(oldfd
, newfd
);
106 uptr
internal_readlink(const char *path
, char *buf
, uptr bufsize
) {
107 return readlink(path
, buf
, bufsize
);
110 uptr
internal_sched_yield() {
111 return sched_yield();
114 void internal__exit(int exitcode
) {
118 uptr
internal_getpid() {
122 int internal_sigaction(int signum
, const void *act
, void *oldact
) {
123 return sigaction(signum
,
124 (struct sigaction
*)act
, (struct sigaction
*)oldact
);
127 int internal_fork() {
128 // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
132 uptr
internal_rename(const char *oldpath
, const char *newpath
) {
133 return rename(oldpath
, newpath
);
136 uptr
internal_ftruncate(fd_t fd
, uptr size
) {
137 return ftruncate(fd
, size
);
140 // ----------------- sanitizer_common.h
141 bool FileExists(const char *filename
) {
143 if (stat(filename
, &st
))
145 // Sanity check: filename is a regular file.
146 return S_ISREG(st
.st_mode
);
150 return reinterpret_cast<uptr
>(pthread_self());
153 void GetThreadStackTopAndBottom(bool at_initialization
, uptr
*stack_top
,
154 uptr
*stack_bottom
) {
157 uptr stacksize
= pthread_get_stacksize_np(pthread_self());
158 // pthread_get_stacksize_np() returns an incorrect stack size for the main
159 // thread on Mavericks. See
160 // https://code.google.com/p/address-sanitizer/issues/detail?id=261
161 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS
) && at_initialization
&&
162 stacksize
== (1 << 19)) {
164 CHECK_EQ(getrlimit(RLIMIT_STACK
, &rl
), 0);
165 // Most often rl.rlim_cur will be the desired 8M.
166 if (rl
.rlim_cur
< kMaxThreadStackSize
) {
167 stacksize
= rl
.rlim_cur
;
169 stacksize
= kMaxThreadStackSize
;
172 void *stackaddr
= pthread_get_stackaddr_np(pthread_self());
173 *stack_top
= (uptr
)stackaddr
;
174 *stack_bottom
= *stack_top
- stacksize
;
177 const char *GetEnv(const char *name
) {
178 char ***env_ptr
= _NSGetEnviron();
180 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
181 "called after libSystem_initializer().\n");
184 char **environ
= *env_ptr
;
186 uptr name_len
= internal_strlen(name
);
187 while (*environ
!= 0) {
188 uptr len
= internal_strlen(*environ
);
189 if (len
> name_len
) {
190 const char *p
= *environ
;
191 if (!internal_memcmp(p
, name
, name_len
) &&
192 p
[name_len
] == '=') { // Match.
193 return *environ
+ name_len
+ 1; // String starting after =.
205 void PrepareForSandboxing(__sanitizer_sandbox_arguments
*args
) {
207 // Nothing here for now.
211 return sysconf(_SC_PAGESIZE
);
214 BlockingMutex::BlockingMutex(LinkerInitialized
) {
215 // We assume that OS_SPINLOCK_INIT is zero
218 BlockingMutex::BlockingMutex() {
219 internal_memset(this, 0, sizeof(*this));
222 void BlockingMutex::Lock() {
223 CHECK(sizeof(OSSpinLock
) <= sizeof(opaque_storage_
));
224 CHECK_EQ(OS_SPINLOCK_INIT
, 0);
225 CHECK_NE(owner_
, (uptr
)pthread_self());
226 OSSpinLockLock((OSSpinLock
*)&opaque_storage_
);
228 owner_
= (uptr
)pthread_self();
231 void BlockingMutex::Unlock() {
232 CHECK(owner_
== (uptr
)pthread_self());
234 OSSpinLockUnlock((OSSpinLock
*)&opaque_storage_
);
237 void BlockingMutex::CheckLocked() {
238 CHECK_EQ((uptr
)pthread_self(), owner_
);
252 void GetThreadStackAndTls(bool main
, uptr
*stk_addr
, uptr
*stk_size
,
253 uptr
*tls_addr
, uptr
*tls_size
) {
255 uptr stack_top
, stack_bottom
;
256 GetThreadStackTopAndBottom(main
, &stack_top
, &stack_bottom
);
257 *stk_addr
= stack_bottom
;
258 *stk_size
= stack_top
- stack_bottom
;
269 uptr
GetListOfModules(LoadedModule
*modules
, uptr max_modules
,
270 string_predicate_t filter
) {
271 MemoryMappingLayout
memory_mapping(false);
272 return memory_mapping
.DumpListOfModules(modules
, max_modules
, filter
);
275 bool IsDeadlySignal(int signum
) {
276 return (signum
== SIGSEGV
|| signum
== SIGBUS
) && common_flags()->handle_segv
;
279 MacosVersion cached_macos_version
= MACOS_VERSION_UNINITIALIZED
;
281 MacosVersion
GetMacosVersionInternal() {
282 int mib
[2] = { CTL_KERN
, KERN_OSRELEASE
};
284 uptr len
= 0, maxlen
= sizeof(version
) / sizeof(version
[0]);
285 for (uptr i
= 0; i
< maxlen
; i
++) version
[i
] = '\0';
286 // Get the version length.
287 CHECK_NE(sysctl(mib
, 2, 0, &len
, 0, 0), -1);
288 CHECK_LT(len
, maxlen
);
289 CHECK_NE(sysctl(mib
, 2, version
, &len
, 0, 0), -1);
290 switch (version
[0]) {
291 case '9': return MACOS_VERSION_LEOPARD
;
293 switch (version
[1]) {
294 case '0': return MACOS_VERSION_SNOW_LEOPARD
;
295 case '1': return MACOS_VERSION_LION
;
296 case '2': return MACOS_VERSION_MOUNTAIN_LION
;
297 case '3': return MACOS_VERSION_MAVERICKS
;
298 case '4': return MACOS_VERSION_YOSEMITE
;
299 default: return MACOS_VERSION_UNKNOWN
;
302 default: return MACOS_VERSION_UNKNOWN
;
306 MacosVersion
GetMacosVersion() {
307 atomic_uint32_t
*cache
=
308 reinterpret_cast<atomic_uint32_t
*>(&cached_macos_version
);
309 MacosVersion result
=
310 static_cast<MacosVersion
>(atomic_load(cache
, memory_order_acquire
));
311 if (result
== MACOS_VERSION_UNINITIALIZED
) {
312 result
= GetMacosVersionInternal();
313 atomic_store(cache
, result
, memory_order_release
);
318 } // namespace __sanitizer
320 #endif // SANITIZER_MAC