Home | History | Annotate | Download | only in sanitizer_common
      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