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 <pthread.h> 35#include <sched.h> 36#include <signal.h> 37#include <sys/mman.h> 38#include <sys/resource.h> 39#include <sys/stat.h> 40#include <sys/sysctl.h> 41#include <sys/types.h> 42#include <unistd.h> 43#include <libkern/OSAtomic.h> 44#include <errno.h> 45 46namespace __sanitizer { 47 48#include "sanitizer_syscall_generic.inc" 49 50// ---------------------- sanitizer_libc.h 51uptr internal_mmap(void *addr, size_t length, int prot, int flags, 52 int fd, u64 offset) { 53 return (uptr)mmap(addr, length, prot, flags, fd, offset); 54} 55 56uptr internal_munmap(void *addr, uptr length) { 57 return munmap(addr, length); 58} 59 60uptr internal_close(fd_t fd) { 61 return close(fd); 62} 63 64uptr internal_open(const char *filename, int flags) { 65 return open(filename, flags); 66} 67 68uptr internal_open(const char *filename, int flags, u32 mode) { 69 return open(filename, flags, mode); 70} 71 72uptr OpenFile(const char *filename, bool write) { 73 return internal_open(filename, 74 write ? O_WRONLY | O_CREAT : O_RDONLY, 0660); 75} 76 77uptr internal_read(fd_t fd, void *buf, uptr count) { 78 return read(fd, buf, count); 79} 80 81uptr internal_write(fd_t fd, const void *buf, uptr count) { 82 return write(fd, buf, count); 83} 84 85uptr internal_stat(const char *path, void *buf) { 86 return stat(path, (struct stat *)buf); 87} 88 89uptr internal_lstat(const char *path, void *buf) { 90 return lstat(path, (struct stat *)buf); 91} 92 93uptr internal_fstat(fd_t fd, void *buf) { 94 return fstat(fd, (struct stat *)buf); 95} 96 97uptr internal_filesize(fd_t fd) { 98 struct stat st; 99 if (internal_fstat(fd, &st)) 100 return -1; 101 return (uptr)st.st_size; 102} 103 104uptr internal_dup2(int oldfd, int newfd) { 105 return dup2(oldfd, newfd); 106} 107 108uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 109 return readlink(path, buf, bufsize); 110} 111 112uptr internal_sched_yield() { 113 return sched_yield(); 114} 115 116void internal__exit(int exitcode) { 117 _exit(exitcode); 118} 119 120uptr internal_getpid() { 121 return getpid(); 122} 123 124int internal_sigaction(int signum, const void *act, void *oldact) { 125 return sigaction(signum, 126 (struct sigaction *)act, (struct sigaction *)oldact); 127} 128 129int internal_fork() { 130 // TODO(glider): this may call user's pthread_atfork() handlers which is bad. 131 return fork(); 132} 133 134uptr internal_rename(const char *oldpath, const char *newpath) { 135 return rename(oldpath, newpath); 136} 137 138uptr internal_ftruncate(fd_t fd, uptr size) { 139 return ftruncate(fd, size); 140} 141 142// ----------------- sanitizer_common.h 143bool FileExists(const char *filename) { 144 struct stat st; 145 if (stat(filename, &st)) 146 return false; 147 // Sanity check: filename is a regular file. 148 return S_ISREG(st.st_mode); 149} 150 151uptr GetTid() { 152 return reinterpret_cast<uptr>(pthread_self()); 153} 154 155void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 156 uptr *stack_bottom) { 157 CHECK(stack_top); 158 CHECK(stack_bottom); 159 uptr stacksize = pthread_get_stacksize_np(pthread_self()); 160 // pthread_get_stacksize_np() returns an incorrect stack size for the main 161 // thread on Mavericks. See 162 // https://code.google.com/p/address-sanitizer/issues/detail?id=261 163 if ((GetMacosVersion() == MACOS_VERSION_MAVERICKS) && at_initialization && 164 stacksize == (1 << 19)) { 165 struct rlimit rl; 166 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); 167 // Most often rl.rlim_cur will be the desired 8M. 168 if (rl.rlim_cur < kMaxThreadStackSize) { 169 stacksize = rl.rlim_cur; 170 } else { 171 stacksize = kMaxThreadStackSize; 172 } 173 } 174 void *stackaddr = pthread_get_stackaddr_np(pthread_self()); 175 *stack_top = (uptr)stackaddr; 176 *stack_bottom = *stack_top - stacksize; 177} 178 179const char *GetEnv(const char *name) { 180 char ***env_ptr = _NSGetEnviron(); 181 if (!env_ptr) { 182 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " 183 "called after libSystem_initializer().\n"); 184 CHECK(env_ptr); 185 } 186 char **environ = *env_ptr; 187 CHECK(environ); 188 uptr name_len = internal_strlen(name); 189 while (*environ != 0) { 190 uptr len = internal_strlen(*environ); 191 if (len > name_len) { 192 const char *p = *environ; 193 if (!internal_memcmp(p, name, name_len) && 194 p[name_len] == '=') { // Match. 195 return *environ + name_len + 1; // String starting after =. 196 } 197 } 198 environ++; 199 } 200 return 0; 201} 202 203void ReExec() { 204 UNIMPLEMENTED(); 205} 206 207void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { 208 (void)args; 209 // Nothing here for now. 210} 211 212uptr GetPageSize() { 213 return sysconf(_SC_PAGESIZE); 214} 215 216BlockingMutex::BlockingMutex(LinkerInitialized) { 217 // We assume that OS_SPINLOCK_INIT is zero 218} 219 220BlockingMutex::BlockingMutex() { 221 internal_memset(this, 0, sizeof(*this)); 222} 223 224void BlockingMutex::Lock() { 225 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); 226 CHECK_EQ(OS_SPINLOCK_INIT, 0); 227 CHECK_NE(owner_, (uptr)pthread_self()); 228 OSSpinLockLock((OSSpinLock*)&opaque_storage_); 229 CHECK(!owner_); 230 owner_ = (uptr)pthread_self(); 231} 232 233void BlockingMutex::Unlock() { 234 CHECK(owner_ == (uptr)pthread_self()); 235 owner_ = 0; 236 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); 237} 238 239void BlockingMutex::CheckLocked() { 240 CHECK_EQ((uptr)pthread_self(), owner_); 241} 242 243u64 NanoTime() { 244 return 0; 245} 246 247uptr GetTlsSize() { 248 return 0; 249} 250 251void InitTlsSize() { 252} 253 254void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 255 uptr *tls_addr, uptr *tls_size) { 256#ifndef SANITIZER_GO 257 uptr stack_top, stack_bottom; 258 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 259 *stk_addr = stack_bottom; 260 *stk_size = stack_top - stack_bottom; 261 *tls_addr = 0; 262 *tls_size = 0; 263#else 264 *stk_addr = 0; 265 *stk_size = 0; 266 *tls_addr = 0; 267 *tls_size = 0; 268#endif 269} 270 271uptr GetListOfModules(LoadedModule *modules, uptr max_modules, 272 string_predicate_t filter) { 273 MemoryMappingLayout memory_mapping(false); 274 return memory_mapping.DumpListOfModules(modules, max_modules, filter); 275} 276 277bool IsDeadlySignal(int signum) { 278 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; 279} 280 281MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; 282 283MacosVersion GetMacosVersionInternal() { 284 int mib[2] = { CTL_KERN, KERN_OSRELEASE }; 285 char version[100]; 286 uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); 287 for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; 288 // Get the version length. 289 CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1); 290 CHECK_LT(len, maxlen); 291 CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1); 292 switch (version[0]) { 293 case '9': return MACOS_VERSION_LEOPARD; 294 case '1': { 295 switch (version[1]) { 296 case '0': return MACOS_VERSION_SNOW_LEOPARD; 297 case '1': return MACOS_VERSION_LION; 298 case '2': return MACOS_VERSION_MOUNTAIN_LION; 299 case '3': return MACOS_VERSION_MAVERICKS; 300 default: return MACOS_VERSION_UNKNOWN; 301 } 302 } 303 default: return MACOS_VERSION_UNKNOWN; 304 } 305} 306 307MacosVersion GetMacosVersion() { 308 atomic_uint32_t *cache = 309 reinterpret_cast<atomic_uint32_t*>(&cached_macos_version); 310 MacosVersion result = 311 static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire)); 312 if (result == MACOS_VERSION_UNINITIALIZED) { 313 result = GetMacosVersionInternal(); 314 atomic_store(cache, result, memory_order_release); 315 } 316 return result; 317} 318 319} // namespace __sanitizer 320 321#endif // SANITIZER_MAC 322