2012-06-04 22:27:50 +08:00
|
|
|
//===-- sanitizer_mac.cc --------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2014-02-03 23:32:19 +08:00
|
|
|
// This file is shared between various sanitizers' runtime libraries and
|
|
|
|
// implements OSX-specific functions.
|
2012-06-04 22:27:50 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-03-19 22:33:38 +08:00
|
|
|
#include "sanitizer_platform.h"
|
|
|
|
#if SANITIZER_MAC
|
|
|
|
|
2013-02-06 22:41:15 +08:00
|
|
|
// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
|
|
|
|
// the clients will most certainly use 64-bit ones as well.
|
|
|
|
#ifndef _DARWIN_USE_64_BIT_INODE
|
|
|
|
#define _DARWIN_USE_64_BIT_INODE 1
|
|
|
|
#endif
|
|
|
|
#include <stdio.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2012-06-07 15:13:46 +08:00
|
|
|
#include "sanitizer_common.h"
|
2014-01-31 21:10:07 +08:00
|
|
|
#include "sanitizer_flags.h"
|
2012-06-05 22:25:27 +08:00
|
|
|
#include "sanitizer_internal_defs.h"
|
2012-06-04 22:27:50 +08:00
|
|
|
#include "sanitizer_libc.h"
|
2014-02-03 23:32:19 +08:00
|
|
|
#include "sanitizer_mac.h"
|
2013-09-10 22:36:16 +08:00
|
|
|
#include "sanitizer_placement_new.h"
|
2015-05-13 05:30:16 +08:00
|
|
|
#include "sanitizer_platform_limits_posix.h"
|
2012-06-07 14:15:12 +08:00
|
|
|
#include "sanitizer_procmaps.h"
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2015-06-24 05:39:49 +08:00
|
|
|
#if !SANITIZER_IOS
|
2012-06-14 22:07:21 +08:00
|
|
|
#include <crt_externs.h> // for _NSGetEnviron
|
2015-06-24 05:39:49 +08:00
|
|
|
#else
|
|
|
|
extern char **environ;
|
|
|
|
#endif
|
|
|
|
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
#if defined(__has_include) && __has_include(<os/trace.h>)
|
|
|
|
#define SANITIZER_OS_TRACE 1
|
|
|
|
#include <os/trace.h>
|
|
|
|
#else
|
|
|
|
#define SANITIZER_OS_TRACE 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <asl.h>
|
2015-05-13 04:47:21 +08:00
|
|
|
#include <errno.h>
|
2012-06-07 15:13:46 +08:00
|
|
|
#include <fcntl.h>
|
2015-05-13 04:47:21 +08:00
|
|
|
#include <libkern/OSAtomic.h>
|
2015-02-27 11:12:19 +08:00
|
|
|
#include <mach-o/dyld.h>
|
2015-05-13 04:47:21 +08:00
|
|
|
#include <mach/mach.h>
|
2015-10-28 04:12:53 +08:00
|
|
|
#include <mach/vm_statistics.h>
|
2012-06-07 15:13:46 +08:00
|
|
|
#include <pthread.h>
|
2012-06-18 16:44:30 +08:00
|
|
|
#include <sched.h>
|
2014-01-31 21:10:07 +08:00
|
|
|
#include <signal.h>
|
2015-02-27 11:12:19 +08:00
|
|
|
#include <stdlib.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
#include <sys/mman.h>
|
2012-06-07 15:13:46 +08:00
|
|
|
#include <sys/resource.h>
|
2012-06-05 15:05:10 +08:00
|
|
|
#include <sys/stat.h>
|
2014-02-03 23:32:19 +08:00
|
|
|
#include <sys/sysctl.h>
|
2012-06-05 15:05:10 +08:00
|
|
|
#include <sys/types.h>
|
2012-06-05 16:32:53 +08:00
|
|
|
#include <unistd.h>
|
2015-11-20 22:28:33 +08:00
|
|
|
#include <util.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
|
|
|
|
namespace __sanitizer {
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
#include "sanitizer_syscall_generic.inc"
|
|
|
|
|
2012-06-07 15:13:46 +08:00
|
|
|
// ---------------------- sanitizer_libc.h
|
2013-05-08 23:07:12 +08:00
|
|
|
uptr internal_mmap(void *addr, size_t length, int prot, int flags,
|
|
|
|
int fd, u64 offset) {
|
2015-10-28 04:12:53 +08:00
|
|
|
if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL);
|
2013-05-08 23:07:12 +08:00
|
|
|
return (uptr)mmap(addr, length, prot, flags, fd, offset);
|
2012-06-04 22:27:50 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 23:07:12 +08:00
|
|
|
uptr internal_munmap(void *addr, uptr length) {
|
2012-06-05 17:49:25 +08:00
|
|
|
return munmap(addr, length);
|
|
|
|
}
|
|
|
|
|
2015-04-10 23:02:19 +08:00
|
|
|
int internal_mprotect(void *addr, uptr length, int prot) {
|
|
|
|
return mprotect(addr, length, prot);
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_close(fd_t fd) {
|
2012-06-05 16:32:53 +08:00
|
|
|
return close(fd);
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_open(const char *filename, int flags) {
|
2013-02-01 23:58:46 +08:00
|
|
|
return open(filename, flags);
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_open(const char *filename, int flags, u32 mode) {
|
2013-02-01 23:58:46 +08:00
|
|
|
return open(filename, flags, mode);
|
|
|
|
}
|
|
|
|
|
2012-06-05 16:32:53 +08:00
|
|
|
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
|
|
|
return read(fd, buf, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
|
|
|
return write(fd, buf, count);
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_stat(const char *path, void *buf) {
|
2013-02-04 18:31:39 +08:00
|
|
|
return stat(path, (struct stat *)buf);
|
2013-02-04 18:16:50 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_lstat(const char *path, void *buf) {
|
2013-02-04 18:31:39 +08:00
|
|
|
return lstat(path, (struct stat *)buf);
|
2013-02-04 18:16:50 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_fstat(fd_t fd, void *buf) {
|
2013-02-04 18:31:39 +08:00
|
|
|
return fstat(fd, (struct stat *)buf);
|
2013-02-04 18:16:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-06 15:30:33 +08:00
|
|
|
uptr internal_filesize(fd_t fd) {
|
2012-08-02 18:09:31 +08:00
|
|
|
struct stat st;
|
2013-02-04 18:16:50 +08:00
|
|
|
if (internal_fstat(fd, &st))
|
2012-06-06 15:30:33 +08:00
|
|
|
return -1;
|
|
|
|
return (uptr)st.st_size;
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_dup2(int oldfd, int newfd) {
|
2012-06-06 15:30:33 +08:00
|
|
|
return dup2(oldfd, newfd);
|
|
|
|
}
|
|
|
|
|
2012-09-05 22:48:24 +08:00
|
|
|
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
|
|
|
return readlink(path, buf, bufsize);
|
|
|
|
}
|
|
|
|
|
2014-12-29 10:18:59 +08:00
|
|
|
uptr internal_unlink(const char *path) {
|
|
|
|
return unlink(path);
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_sched_yield() {
|
2012-06-18 16:44:30 +08:00
|
|
|
return sched_yield();
|
|
|
|
}
|
|
|
|
|
2013-02-20 21:54:32 +08:00
|
|
|
void internal__exit(int exitcode) {
|
|
|
|
_exit(exitcode);
|
|
|
|
}
|
|
|
|
|
2013-05-18 00:56:53 +08:00
|
|
|
uptr internal_getpid() {
|
|
|
|
return getpid();
|
|
|
|
}
|
|
|
|
|
2014-01-31 21:10:07 +08:00
|
|
|
int internal_sigaction(int signum, const void *act, void *oldact) {
|
|
|
|
return sigaction(signum,
|
|
|
|
(struct sigaction *)act, (struct sigaction *)oldact);
|
|
|
|
}
|
|
|
|
|
2015-05-13 04:56:44 +08:00
|
|
|
void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }
|
|
|
|
|
|
|
|
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
|
|
|
|
__sanitizer_sigset_t *oldset) {
|
|
|
|
return sigprocmask(how, set, oldset);
|
|
|
|
}
|
|
|
|
|
2015-11-20 22:28:33 +08:00
|
|
|
// Doesn't call pthread_atfork() handlers.
|
|
|
|
extern "C" pid_t __fork(void);
|
|
|
|
|
2014-05-14 00:17:54 +08:00
|
|
|
int internal_fork() {
|
2015-11-20 22:28:33 +08:00
|
|
|
return __fork();
|
|
|
|
}
|
|
|
|
|
|
|
|
int internal_forkpty(int *amaster) {
|
|
|
|
int master, slave;
|
|
|
|
if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1;
|
|
|
|
int pid = __fork();
|
|
|
|
if (pid == -1) {
|
|
|
|
close(master);
|
|
|
|
close(slave);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (pid == 0) {
|
|
|
|
close(master);
|
|
|
|
CHECK_EQ(login_tty(slave), 0);
|
|
|
|
} else {
|
|
|
|
*amaster = master;
|
|
|
|
close(slave);
|
|
|
|
}
|
|
|
|
return pid;
|
2014-05-14 00:17:54 +08:00
|
|
|
}
|
|
|
|
|
2014-05-27 20:37:52 +08:00
|
|
|
uptr internal_rename(const char *oldpath, const char *newpath) {
|
|
|
|
return rename(oldpath, newpath);
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_ftruncate(fd_t fd, uptr size) {
|
|
|
|
return ftruncate(fd, size);
|
|
|
|
}
|
|
|
|
|
2012-06-07 15:13:46 +08:00
|
|
|
// ----------------- sanitizer_common.h
|
2012-11-09 22:45:30 +08:00
|
|
|
bool FileExists(const char *filename) {
|
|
|
|
struct stat st;
|
|
|
|
if (stat(filename, &st))
|
|
|
|
return false;
|
|
|
|
// Sanity check: filename is a regular file.
|
|
|
|
return S_ISREG(st.st_mode);
|
|
|
|
}
|
|
|
|
|
2012-10-02 20:58:14 +08:00
|
|
|
uptr GetTid() {
|
|
|
|
return reinterpret_cast<uptr>(pthread_self());
|
|
|
|
}
|
|
|
|
|
2012-06-07 15:32:00 +08:00
|
|
|
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
2012-06-07 15:13:46 +08:00
|
|
|
uptr *stack_bottom) {
|
|
|
|
CHECK(stack_top);
|
|
|
|
CHECK(stack_bottom);
|
|
|
|
uptr stacksize = pthread_get_stacksize_np(pthread_self());
|
2014-02-04 00:42:29 +08:00
|
|
|
// pthread_get_stacksize_np() returns an incorrect stack size for the main
|
|
|
|
// thread on Mavericks. See
|
|
|
|
// https://code.google.com/p/address-sanitizer/issues/detail?id=261
|
2014-11-06 02:55:38 +08:00
|
|
|
if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
|
2014-02-04 00:42:29 +08:00
|
|
|
stacksize == (1 << 19)) {
|
|
|
|
struct rlimit rl;
|
|
|
|
CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
|
|
|
|
// Most often rl.rlim_cur will be the desired 8M.
|
|
|
|
if (rl.rlim_cur < kMaxThreadStackSize) {
|
|
|
|
stacksize = rl.rlim_cur;
|
|
|
|
} else {
|
|
|
|
stacksize = kMaxThreadStackSize;
|
|
|
|
}
|
|
|
|
}
|
2012-06-07 15:13:46 +08:00
|
|
|
void *stackaddr = pthread_get_stackaddr_np(pthread_self());
|
|
|
|
*stack_top = (uptr)stackaddr;
|
2012-06-07 15:32:00 +08:00
|
|
|
*stack_bottom = *stack_top - stacksize;
|
2012-06-07 15:13:46 +08:00
|
|
|
}
|
|
|
|
|
2015-06-24 05:39:49 +08:00
|
|
|
char **GetEnviron() {
|
|
|
|
#if !SANITIZER_IOS
|
2012-06-14 22:07:21 +08:00
|
|
|
char ***env_ptr = _NSGetEnviron();
|
2013-11-13 21:34:53 +08:00
|
|
|
if (!env_ptr) {
|
|
|
|
Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
|
|
|
|
"called after libSystem_initializer().\n");
|
|
|
|
CHECK(env_ptr);
|
|
|
|
}
|
2012-06-14 22:07:21 +08:00
|
|
|
char **environ = *env_ptr;
|
2015-06-24 05:39:49 +08:00
|
|
|
#endif
|
2012-06-14 22:07:21 +08:00
|
|
|
CHECK(environ);
|
2015-06-24 05:39:49 +08:00
|
|
|
return environ;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *GetEnv(const char *name) {
|
|
|
|
char **env = GetEnviron();
|
2012-06-14 22:07:21 +08:00
|
|
|
uptr name_len = internal_strlen(name);
|
2015-06-24 05:39:49 +08:00
|
|
|
while (*env != 0) {
|
|
|
|
uptr len = internal_strlen(*env);
|
2012-06-14 22:07:21 +08:00
|
|
|
if (len > name_len) {
|
2015-06-24 05:39:49 +08:00
|
|
|
const char *p = *env;
|
2012-06-14 22:07:21 +08:00
|
|
|
if (!internal_memcmp(p, name, name_len) &&
|
|
|
|
p[name_len] == '=') { // Match.
|
2015-06-24 05:39:49 +08:00
|
|
|
return *env + name_len + 1; // String starting after =.
|
2012-06-14 22:07:21 +08:00
|
|
|
}
|
|
|
|
}
|
2015-06-24 05:39:49 +08:00
|
|
|
env++;
|
2012-06-14 22:07:21 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2012-06-07 15:13:46 +08:00
|
|
|
|
2015-02-27 11:12:19 +08:00
|
|
|
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
|
|
|
|
CHECK_LE(kMaxPathLength, buf_len);
|
|
|
|
|
|
|
|
// On OS X the executable path is saved to the stack by dyld. Reading it
|
|
|
|
// from there is much faster than calling dladdr, especially for large
|
|
|
|
// binaries with symbols.
|
|
|
|
InternalScopedString exe_path(kMaxPathLength);
|
|
|
|
uint32_t size = exe_path.size();
|
|
|
|
if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
|
|
|
|
realpath(exe_path.data(), buf) != 0) {
|
|
|
|
return internal_strlen(buf);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-29 05:01:42 +08:00
|
|
|
uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
|
|
|
|
return ReadBinaryName(buf, buf_len);
|
|
|
|
}
|
|
|
|
|
2012-09-17 17:12:39 +08:00
|
|
|
void ReExec() {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
2013-05-21 01:05:29 +08:00
|
|
|
uptr GetPageSize() {
|
|
|
|
return sysconf(_SC_PAGESIZE);
|
|
|
|
}
|
|
|
|
|
2013-03-14 21:30:56 +08:00
|
|
|
BlockingMutex::BlockingMutex() {
|
|
|
|
internal_memset(this, 0, sizeof(*this));
|
|
|
|
}
|
|
|
|
|
2013-01-14 15:51:39 +08:00
|
|
|
void BlockingMutex::Lock() {
|
|
|
|
CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
|
2013-02-26 20:59:06 +08:00
|
|
|
CHECK_EQ(OS_SPINLOCK_INIT, 0);
|
|
|
|
CHECK_NE(owner_, (uptr)pthread_self());
|
2013-01-14 15:51:39 +08:00
|
|
|
OSSpinLockLock((OSSpinLock*)&opaque_storage_);
|
|
|
|
CHECK(!owner_);
|
|
|
|
owner_ = (uptr)pthread_self();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BlockingMutex::Unlock() {
|
|
|
|
CHECK(owner_ == (uptr)pthread_self());
|
|
|
|
owner_ = 0;
|
|
|
|
OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:45:20 +08:00
|
|
|
void BlockingMutex::CheckLocked() {
|
|
|
|
CHECK_EQ((uptr)pthread_self(), owner_);
|
|
|
|
}
|
|
|
|
|
2013-06-06 21:00:32 +08:00
|
|
|
u64 NanoTime() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-13 16:19:53 +08:00
|
|
|
uptr GetTlsSize() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitTlsSize() {
|
|
|
|
}
|
|
|
|
|
2013-05-07 22:41:43 +08:00
|
|
|
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
|
|
|
uptr *tls_addr, uptr *tls_size) {
|
2013-06-06 21:20:40 +08:00
|
|
|
#ifndef SANITIZER_GO
|
2013-05-07 22:41:43 +08:00
|
|
|
uptr stack_top, stack_bottom;
|
|
|
|
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
|
|
|
|
*stk_addr = stack_bottom;
|
|
|
|
*stk_size = stack_top - stack_bottom;
|
|
|
|
*tls_addr = 0;
|
|
|
|
*tls_size = 0;
|
2013-06-06 21:20:40 +08:00
|
|
|
#else
|
|
|
|
*stk_addr = 0;
|
|
|
|
*stk_size = 0;
|
|
|
|
*tls_addr = 0;
|
|
|
|
*tls_size = 0;
|
|
|
|
#endif
|
2013-05-07 22:41:43 +08:00
|
|
|
}
|
|
|
|
|
2013-09-10 22:36:16 +08:00
|
|
|
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
|
|
|
|
string_predicate_t filter) {
|
|
|
|
MemoryMappingLayout memory_mapping(false);
|
2013-12-25 16:39:38 +08:00
|
|
|
return memory_mapping.DumpListOfModules(modules, max_modules, filter);
|
2013-09-10 22:36:16 +08:00
|
|
|
}
|
|
|
|
|
2014-01-31 21:10:07 +08:00
|
|
|
bool IsDeadlySignal(int signum) {
|
|
|
|
return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
|
|
|
|
}
|
|
|
|
|
2014-02-03 23:32:19 +08:00
|
|
|
MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
|
|
|
|
|
|
|
|
MacosVersion GetMacosVersionInternal() {
|
|
|
|
int mib[2] = { CTL_KERN, KERN_OSRELEASE };
|
|
|
|
char version[100];
|
|
|
|
uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
|
|
|
|
for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
|
|
|
|
// Get the version length.
|
|
|
|
CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
|
|
|
|
CHECK_LT(len, maxlen);
|
|
|
|
CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
|
|
|
|
switch (version[0]) {
|
|
|
|
case '9': return MACOS_VERSION_LEOPARD;
|
|
|
|
case '1': {
|
|
|
|
switch (version[1]) {
|
|
|
|
case '0': return MACOS_VERSION_SNOW_LEOPARD;
|
|
|
|
case '1': return MACOS_VERSION_LION;
|
|
|
|
case '2': return MACOS_VERSION_MOUNTAIN_LION;
|
|
|
|
case '3': return MACOS_VERSION_MAVERICKS;
|
2014-11-06 02:53:22 +08:00
|
|
|
case '4': return MACOS_VERSION_YOSEMITE;
|
2014-12-16 12:46:15 +08:00
|
|
|
default:
|
|
|
|
if (IsDigit(version[1]))
|
|
|
|
return MACOS_VERSION_UNKNOWN_NEWER;
|
|
|
|
else
|
|
|
|
return MACOS_VERSION_UNKNOWN;
|
2014-02-03 23:32:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
default: return MACOS_VERSION_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MacosVersion GetMacosVersion() {
|
|
|
|
atomic_uint32_t *cache =
|
|
|
|
reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
|
|
|
|
MacosVersion result =
|
|
|
|
static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
|
|
|
|
if (result == MACOS_VERSION_UNINITIALIZED) {
|
|
|
|
result = GetMacosVersionInternal();
|
|
|
|
atomic_store(cache, result, memory_order_release);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-12-09 09:22:59 +08:00
|
|
|
uptr GetRSS() {
|
2015-05-13 04:47:21 +08:00
|
|
|
struct task_basic_info info;
|
|
|
|
unsigned count = TASK_BASIC_INFO_COUNT;
|
|
|
|
kern_return_t result =
|
|
|
|
task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count);
|
|
|
|
if (UNLIKELY(result != KERN_SUCCESS)) {
|
|
|
|
Report("Cannot get task info. Error: %d\n", result);
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
return info.resident_size;
|
2014-12-09 09:22:59 +08:00
|
|
|
}
|
|
|
|
|
2015-11-11 10:44:19 +08:00
|
|
|
void *internal_start_thread(void(*func)(void *arg), void *arg) {
|
|
|
|
// Start the thread with signals blocked, otherwise it can steal user signals.
|
|
|
|
__sanitizer_sigset_t set, old;
|
|
|
|
internal_sigfillset(&set);
|
|
|
|
internal_sigprocmask(SIG_SETMASK, &set, &old);
|
|
|
|
pthread_t th;
|
|
|
|
pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
|
|
|
|
internal_sigprocmask(SIG_SETMASK, &old, 0);
|
|
|
|
return th;
|
|
|
|
}
|
|
|
|
|
|
|
|
void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
|
2014-12-17 03:13:01 +08:00
|
|
|
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
static BlockingMutex syslog_lock(LINKER_INITIALIZED);
|
|
|
|
|
|
|
|
void WriteOneLineToSyslog(const char *s) {
|
|
|
|
syslog_lock.CheckLocked();
|
|
|
|
asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogFullErrorReport(const char *buffer) {
|
|
|
|
// Log with os_trace. This will make it into the crash log.
|
|
|
|
#if SANITIZER_OS_TRACE
|
|
|
|
if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) {
|
|
|
|
// os_trace requires the message (format parameter) to be a string literal.
|
|
|
|
if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
|
|
|
|
sizeof("AddressSanitizer") - 1) == 0)
|
|
|
|
os_trace("Address Sanitizer reported a failure.");
|
|
|
|
else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
|
|
|
|
sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
|
|
|
|
os_trace("Undefined Behavior Sanitizer reported a failure.");
|
|
|
|
else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
|
|
|
|
sizeof("ThreadSanitizer") - 1) == 0)
|
|
|
|
os_trace("Thread Sanitizer reported a failure.");
|
|
|
|
else
|
|
|
|
os_trace("Sanitizer tool reported a failure.");
|
|
|
|
|
|
|
|
if (common_flags()->log_to_syslog)
|
|
|
|
os_trace("Consult syslog for more information.");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Log to syslog.
|
|
|
|
// The logging on OS X may call pthread_create so we need the threading
|
|
|
|
// environment to be fully initialized. Also, this should never be called when
|
|
|
|
// holding the thread registry lock since that may result in a deadlock. If
|
|
|
|
// the reporting thread holds the thread registry mutex, and asl_log waits
|
|
|
|
// for GCD to dispatch a new thread, the process will deadlock, because the
|
|
|
|
// pthread_create wrapper needs to acquire the lock as well.
|
|
|
|
BlockingMutexLock l(&syslog_lock);
|
|
|
|
if (common_flags()->log_to_syslog)
|
|
|
|
WriteToSyslog(buffer);
|
|
|
|
}
|
|
|
|
|
2015-03-03 01:36:02 +08:00
|
|
|
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
2015-06-24 05:39:49 +08:00
|
|
|
# if defined(__aarch64__)
|
|
|
|
*pc = ucontext->uc_mcontext->__ss.__pc;
|
|
|
|
# if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__fp;
|
|
|
|
# else
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__lr;
|
|
|
|
# endif
|
|
|
|
*sp = ucontext->uc_mcontext->__ss.__sp;
|
|
|
|
# elif defined(__x86_64__)
|
2015-03-03 01:36:02 +08:00
|
|
|
*pc = ucontext->uc_mcontext->__ss.__rip;
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__rbp;
|
|
|
|
*sp = ucontext->uc_mcontext->__ss.__rsp;
|
2015-06-24 05:39:49 +08:00
|
|
|
# elif defined(__arm__)
|
|
|
|
*pc = ucontext->uc_mcontext->__ss.__pc;
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__r[7];
|
|
|
|
*sp = ucontext->uc_mcontext->__ss.__sp;
|
|
|
|
# elif defined(__i386__)
|
2015-03-03 01:36:02 +08:00
|
|
|
*pc = ucontext->uc_mcontext->__ss.__eip;
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__ebp;
|
|
|
|
*sp = ucontext->uc_mcontext->__ss.__esp;
|
2015-06-24 05:39:49 +08:00
|
|
|
# else
|
|
|
|
# error "Unknown architecture"
|
|
|
|
# endif
|
2015-03-03 01:36:02 +08:00
|
|
|
}
|
|
|
|
|
2012-06-04 22:27:50 +08:00
|
|
|
} // namespace __sanitizer
|
|
|
|
|
2013-04-03 15:24:35 +08:00
|
|
|
#endif // SANITIZER_MAC
|