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 // ----------------- sanitizer_common.h
133 bool FileExists(const char *filename
) {
135 if (stat(filename
, &st
))
137 // Sanity check: filename is a regular file.
138 return S_ISREG(st
.st_mode
);
142 return reinterpret_cast<uptr
>(pthread_self());
145 void GetThreadStackTopAndBottom(bool at_initialization
, uptr
*stack_top
,
146 uptr
*stack_bottom
) {
149 uptr stacksize
= pthread_get_stacksize_np(pthread_self());
150 // pthread_get_stacksize_np() returns an incorrect stack size for the main
151 // thread on Mavericks. See
152 // https://code.google.com/p/address-sanitizer/issues/detail?id=261
153 if ((GetMacosVersion() == MACOS_VERSION_MAVERICKS
) && at_initialization
&&
154 stacksize
== (1 << 19)) {
156 CHECK_EQ(getrlimit(RLIMIT_STACK
, &rl
), 0);
157 // Most often rl.rlim_cur will be the desired 8M.
158 if (rl
.rlim_cur
< kMaxThreadStackSize
) {
159 stacksize
= rl
.rlim_cur
;
161 stacksize
= kMaxThreadStackSize
;
164 void *stackaddr
= pthread_get_stackaddr_np(pthread_self());
165 *stack_top
= (uptr
)stackaddr
;
166 *stack_bottom
= *stack_top
- stacksize
;
169 const char *GetEnv(const char *name
) {
170 char ***env_ptr
= _NSGetEnviron();
172 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
173 "called after libSystem_initializer().\n");
176 char **environ
= *env_ptr
;
178 uptr name_len
= internal_strlen(name
);
179 while (*environ
!= 0) {
180 uptr len
= internal_strlen(*environ
);
181 if (len
> name_len
) {
182 const char *p
= *environ
;
183 if (!internal_memcmp(p
, name
, name_len
) &&
184 p
[name_len
] == '=') { // Match.
185 return *environ
+ name_len
+ 1; // String starting after =.
197 void PrepareForSandboxing(__sanitizer_sandbox_arguments
*args
) {
199 // Nothing here for now.
203 return sysconf(_SC_PAGESIZE
);
206 BlockingMutex::BlockingMutex(LinkerInitialized
) {
207 // We assume that OS_SPINLOCK_INIT is zero
210 BlockingMutex::BlockingMutex() {
211 internal_memset(this, 0, sizeof(*this));
214 void BlockingMutex::Lock() {
215 CHECK(sizeof(OSSpinLock
) <= sizeof(opaque_storage_
));
216 CHECK_EQ(OS_SPINLOCK_INIT
, 0);
217 CHECK_NE(owner_
, (uptr
)pthread_self());
218 OSSpinLockLock((OSSpinLock
*)&opaque_storage_
);
220 owner_
= (uptr
)pthread_self();
223 void BlockingMutex::Unlock() {
224 CHECK(owner_
== (uptr
)pthread_self());
226 OSSpinLockUnlock((OSSpinLock
*)&opaque_storage_
);
229 void BlockingMutex::CheckLocked() {
230 CHECK_EQ((uptr
)pthread_self(), owner_
);
244 void GetThreadStackAndTls(bool main
, uptr
*stk_addr
, uptr
*stk_size
,
245 uptr
*tls_addr
, uptr
*tls_size
) {
247 uptr stack_top
, stack_bottom
;
248 GetThreadStackTopAndBottom(main
, &stack_top
, &stack_bottom
);
249 *stk_addr
= stack_bottom
;
250 *stk_size
= stack_top
- stack_bottom
;
261 uptr
GetListOfModules(LoadedModule
*modules
, uptr max_modules
,
262 string_predicate_t filter
) {
263 MemoryMappingLayout
memory_mapping(false);
264 return memory_mapping
.DumpListOfModules(modules
, max_modules
, filter
);
267 bool IsDeadlySignal(int signum
) {
268 return (signum
== SIGSEGV
|| signum
== SIGBUS
) && common_flags()->handle_segv
;
271 MacosVersion cached_macos_version
= MACOS_VERSION_UNINITIALIZED
;
273 MacosVersion
GetMacosVersionInternal() {
274 int mib
[2] = { CTL_KERN
, KERN_OSRELEASE
};
276 uptr len
= 0, maxlen
= sizeof(version
) / sizeof(version
[0]);
277 for (uptr i
= 0; i
< maxlen
; i
++) version
[i
] = '\0';
278 // Get the version length.
279 CHECK_NE(sysctl(mib
, 2, 0, &len
, 0, 0), -1);
280 CHECK_LT(len
, maxlen
);
281 CHECK_NE(sysctl(mib
, 2, version
, &len
, 0, 0), -1);
282 switch (version
[0]) {
283 case '9': return MACOS_VERSION_LEOPARD
;
285 switch (version
[1]) {
286 case '0': return MACOS_VERSION_SNOW_LEOPARD
;
287 case '1': return MACOS_VERSION_LION
;
288 case '2': return MACOS_VERSION_MOUNTAIN_LION
;
289 case '3': return MACOS_VERSION_MAVERICKS
;
290 default: return MACOS_VERSION_UNKNOWN
;
293 default: return MACOS_VERSION_UNKNOWN
;
297 MacosVersion
GetMacosVersion() {
298 atomic_uint32_t
*cache
=
299 reinterpret_cast<atomic_uint32_t
*>(&cached_macos_version
);
300 MacosVersion result
=
301 static_cast<MacosVersion
>(atomic_load(cache
, memory_order_acquire
));
302 if (result
== MACOS_VERSION_UNINITIALIZED
) {
303 result
= GetMacosVersionInternal();
304 atomic_store(cache
, result
, memory_order_release
);
309 } // namespace __sanitizer
311 #endif // SANITIZER_MAC