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