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 46 namespace __sanitizer { 47 48 #include "sanitizer_syscall_generic.inc" 49 50 // ---------------------- sanitizer_libc.h 51 uptr 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 56 uptr internal_munmap(void *addr, uptr length) { 57 return munmap(addr, length); 58 } 59 60 uptr internal_close(fd_t fd) { 61 return close(fd); 62 } 63 64 uptr internal_open(const char *filename, int flags) { 65 return open(filename, flags); 66 } 67 68 uptr internal_open(const char *filename, int flags, u32 mode) { 69 return open(filename, flags, mode); 70 } 71 72 uptr OpenFile(const char *filename, bool write) { 73 return internal_open(filename, 74 write ? O_WRONLY | O_CREAT : O_RDONLY, 0660); 75 } 76 77 uptr internal_read(fd_t fd, void *buf, uptr count) { 78 return read(fd, buf, count); 79 } 80 81 uptr internal_write(fd_t fd, const void *buf, uptr count) { 82 return write(fd, buf, count); 83 } 84 85 uptr internal_stat(const char *path, void *buf) { 86 return stat(path, (struct stat *)buf); 87 } 88 89 uptr internal_lstat(const char *path, void *buf) { 90 return lstat(path, (struct stat *)buf); 91 } 92 93 uptr internal_fstat(fd_t fd, void *buf) { 94 return fstat(fd, (struct stat *)buf); 95 } 96 97 uptr 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 104 uptr internal_dup2(int oldfd, int newfd) { 105 return dup2(oldfd, newfd); 106 } 107 108 uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 109 return readlink(path, buf, bufsize); 110 } 111 112 uptr internal_sched_yield() { 113 return sched_yield(); 114 } 115 116 void internal__exit(int exitcode) { 117 _exit(exitcode); 118 } 119 120 uptr internal_getpid() { 121 return getpid(); 122 } 123 124 int internal_sigaction(int signum, const void *act, void *oldact) { 125 return sigaction(signum, 126 (struct sigaction *)act, (struct sigaction *)oldact); 127 } 128 129 int internal_fork() { 130 // TODO(glider): this may call user's pthread_atfork() handlers which is bad. 131 return fork(); 132 } 133 134 uptr internal_rename(const char *oldpath, const char *newpath) { 135 return rename(oldpath, newpath); 136 } 137 138 uptr internal_ftruncate(fd_t fd, uptr size) { 139 return ftruncate(fd, size); 140 } 141 142 // ----------------- sanitizer_common.h 143 bool 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 151 uptr GetTid() { 152 return reinterpret_cast<uptr>(pthread_self()); 153 } 154 155 void 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 179 const 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 203 void ReExec() { 204 UNIMPLEMENTED(); 205 } 206 207 void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { 208 (void)args; 209 // Nothing here for now. 210 } 211 212 uptr GetPageSize() { 213 return sysconf(_SC_PAGESIZE); 214 } 215 216 BlockingMutex::BlockingMutex(LinkerInitialized) { 217 // We assume that OS_SPINLOCK_INIT is zero 218 } 219 220 BlockingMutex::BlockingMutex() { 221 internal_memset(this, 0, sizeof(*this)); 222 } 223 224 void 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 233 void BlockingMutex::Unlock() { 234 CHECK(owner_ == (uptr)pthread_self()); 235 owner_ = 0; 236 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); 237 } 238 239 void BlockingMutex::CheckLocked() { 240 CHECK_EQ((uptr)pthread_self(), owner_); 241 } 242 243 u64 NanoTime() { 244 return 0; 245 } 246 247 uptr GetTlsSize() { 248 return 0; 249 } 250 251 void InitTlsSize() { 252 } 253 254 void 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 271 uptr 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 277 bool IsDeadlySignal(int signum) { 278 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; 279 } 280 281 MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; 282 283 MacosVersion 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 307 MacosVersion 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