1//===-- sanitizer_mac.cc --------------------------------------------------===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is shared between various sanitizers' runtime libraries and 9// implements OSX-specific functions. 10//===----------------------------------------------------------------------===// 11 12#include "sanitizer_platform.h" 13#if SANITIZER_MAC 14 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 19#endif 20#include <stdio.h> 21 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" 29 30#include <crt_externs.h> // for _NSGetEnviron 31#include <fcntl.h> 32#include <pthread.h> 33#include <sched.h> 34#include <signal.h> 35#include <sys/mman.h> 36#include <sys/resource.h> 37#include <sys/stat.h> 38#include <sys/sysctl.h> 39#include <sys/types.h> 40#include <unistd.h> 41#include <libkern/OSAtomic.h> 42#include <errno.h> 43 44namespace __sanitizer { 45 46#include "sanitizer_syscall_generic.inc" 47 48// ---------------------- sanitizer_libc.h 49uptr internal_mmap(void *addr, size_t length, int prot, int flags, 50 int fd, u64 offset) { 51 return (uptr)mmap(addr, length, prot, flags, fd, offset); 52} 53 54uptr internal_munmap(void *addr, uptr length) { 55 return munmap(addr, length); 56} 57 58uptr internal_close(fd_t fd) { 59 return close(fd); 60} 61 62uptr internal_open(const char *filename, int flags) { 63 return open(filename, flags); 64} 65 66uptr internal_open(const char *filename, int flags, u32 mode) { 67 return open(filename, flags, mode); 68} 69 70uptr OpenFile(const char *filename, bool write) { 71 return internal_open(filename, 72 write ? O_WRONLY | O_CREAT : O_RDONLY, 0660); 73} 74 75uptr internal_read(fd_t fd, void *buf, uptr count) { 76 return read(fd, buf, count); 77} 78 79uptr internal_write(fd_t fd, const void *buf, uptr count) { 80 return write(fd, buf, count); 81} 82 83uptr internal_stat(const char *path, void *buf) { 84 return stat(path, (struct stat *)buf); 85} 86 87uptr internal_lstat(const char *path, void *buf) { 88 return lstat(path, (struct stat *)buf); 89} 90 91uptr internal_fstat(fd_t fd, void *buf) { 92 return fstat(fd, (struct stat *)buf); 93} 94 95uptr internal_filesize(fd_t fd) { 96 struct stat st; 97 if (internal_fstat(fd, &st)) 98 return -1; 99 return (uptr)st.st_size; 100} 101 102uptr internal_dup2(int oldfd, int newfd) { 103 return dup2(oldfd, newfd); 104} 105 106uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 107 return readlink(path, buf, bufsize); 108} 109 110uptr internal_sched_yield() { 111 return sched_yield(); 112} 113 114void internal__exit(int exitcode) { 115 _exit(exitcode); 116} 117 118uptr internal_getpid() { 119 return getpid(); 120} 121 122int internal_sigaction(int signum, const void *act, void *oldact) { 123 return sigaction(signum, 124 (struct sigaction *)act, (struct sigaction *)oldact); 125} 126 127int internal_fork() { 128 // TODO(glider): this may call user's pthread_atfork() handlers which is bad. 129 return fork(); 130} 131 132uptr internal_rename(const char *oldpath, const char *newpath) { 133 return rename(oldpath, newpath); 134} 135 136uptr internal_ftruncate(fd_t fd, uptr size) { 137 return ftruncate(fd, size); 138} 139 140// ----------------- sanitizer_common.h 141bool FileExists(const char *filename) { 142 struct stat st; 143 if (stat(filename, &st)) 144 return false; 145 // Sanity check: filename is a regular file. 146 return S_ISREG(st.st_mode); 147} 148 149uptr GetTid() { 150 return reinterpret_cast<uptr>(pthread_self()); 151} 152 153void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 154 uptr *stack_bottom) { 155 CHECK(stack_top); 156 CHECK(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)) { 163 struct rlimit rl; 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; 168 } else { 169 stacksize = kMaxThreadStackSize; 170 } 171 } 172 void *stackaddr = pthread_get_stackaddr_np(pthread_self()); 173 *stack_top = (uptr)stackaddr; 174 *stack_bottom = *stack_top - stacksize; 175} 176 177const char *GetEnv(const char *name) { 178 char ***env_ptr = _NSGetEnviron(); 179 if (!env_ptr) { 180 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " 181 "called after libSystem_initializer().\n"); 182 CHECK(env_ptr); 183 } 184 char **environ = *env_ptr; 185 CHECK(environ); 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 =. 194 } 195 } 196 environ++; 197 } 198 return 0; 199} 200 201void ReExec() { 202 UNIMPLEMENTED(); 203} 204 205void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { 206 (void)args; 207 // Nothing here for now. 208} 209 210uptr GetPageSize() { 211 return sysconf(_SC_PAGESIZE); 212} 213 214BlockingMutex::BlockingMutex(LinkerInitialized) { 215 // We assume that OS_SPINLOCK_INIT is zero 216} 217 218BlockingMutex::BlockingMutex() { 219 internal_memset(this, 0, sizeof(*this)); 220} 221 222void 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_); 227 CHECK(!owner_); 228 owner_ = (uptr)pthread_self(); 229} 230 231void BlockingMutex::Unlock() { 232 CHECK(owner_ == (uptr)pthread_self()); 233 owner_ = 0; 234 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); 235} 236 237void BlockingMutex::CheckLocked() { 238 CHECK_EQ((uptr)pthread_self(), owner_); 239} 240 241u64 NanoTime() { 242 return 0; 243} 244 245uptr GetTlsSize() { 246 return 0; 247} 248 249void InitTlsSize() { 250} 251 252void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 253 uptr *tls_addr, uptr *tls_size) { 254#ifndef SANITIZER_GO 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; 259 *tls_addr = 0; 260 *tls_size = 0; 261#else 262 *stk_addr = 0; 263 *stk_size = 0; 264 *tls_addr = 0; 265 *tls_size = 0; 266#endif 267} 268 269uptr 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); 273} 274 275bool IsDeadlySignal(int signum) { 276 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; 277} 278 279MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; 280 281MacosVersion GetMacosVersionInternal() { 282 int mib[2] = { CTL_KERN, KERN_OSRELEASE }; 283 char version[100]; 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; 292 case '1': { 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: 300 if (IsDigit(version[1])) 301 return MACOS_VERSION_UNKNOWN_NEWER; 302 else 303 return MACOS_VERSION_UNKNOWN; 304 } 305 } 306 default: return MACOS_VERSION_UNKNOWN; 307 } 308} 309 310MacosVersion GetMacosVersion() { 311 atomic_uint32_t *cache = 312 reinterpret_cast<atomic_uint32_t*>(&cached_macos_version); 313 MacosVersion result = 314 static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire)); 315 if (result == MACOS_VERSION_UNINITIALIZED) { 316 result = GetMacosVersionInternal(); 317 atomic_store(cache, result, memory_order_release); 318 } 319 return result; 320} 321 322} // namespace __sanitizer 323 324#endif // SANITIZER_MAC 325