2019-07-31 18:51:27 +00:00
|
|
|
//===-- sanitizer_mac.cpp -------------------------------------------------===//
|
2012-06-04 14:27:50 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2012-06-04 14:27:50 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2014-02-03 15:32:19 +00:00
|
|
|
// This file is shared between various sanitizers' runtime libraries and
|
|
|
|
// implements OSX-specific functions.
|
2012-06-04 14:27:50 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-03-19 14:33:38 +00:00
|
|
|
#include "sanitizer_platform.h"
|
2022-05-23 14:35:42 -07:00
|
|
|
#if SANITIZER_APPLE
|
2015-11-20 18:42:01 +00:00
|
|
|
#include "sanitizer_mac.h"
|
2019-08-19 18:12:15 +00:00
|
|
|
#include "interception/interception.h"
|
2013-03-19 14:33:38 +00:00
|
|
|
|
2013-02-06 14:41:15 +00: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 14:27:50 +00:00
|
|
|
|
2012-06-07 07:13:46 +00:00
|
|
|
#include "sanitizer_common.h"
|
2017-07-22 01:46:40 +00:00
|
|
|
#include "sanitizer_file.h"
|
2014-01-31 13:10:07 +00:00
|
|
|
#include "sanitizer_flags.h"
|
2022-02-11 22:53:19 +00:00
|
|
|
#include "sanitizer_interface_internal.h"
|
2012-06-05 14:25:27 +00:00
|
|
|
#include "sanitizer_internal_defs.h"
|
2012-06-04 14:27:50 +00:00
|
|
|
#include "sanitizer_libc.h"
|
2015-05-12 21:30:16 +00:00
|
|
|
#include "sanitizer_platform_limits_posix.h"
|
2012-06-07 06:15:12 +00:00
|
|
|
#include "sanitizer_procmaps.h"
|
2020-05-06 19:05:31 -07:00
|
|
|
#include "sanitizer_ptrauth.h"
|
2012-06-04 14:27:50 +00:00
|
|
|
|
2015-06-23 21:39:49 +00:00
|
|
|
#if !SANITIZER_IOS
|
2012-06-14 14:07:21 +00:00
|
|
|
#include <crt_externs.h> // for _NSGetEnviron
|
2015-06-23 21:39:49 +00: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-20 18:41:44 +00: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
|
|
|
|
|
2021-02-23 09:23:02 -08:00
|
|
|
// import new crash reporting api
|
|
|
|
#if defined(__has_include) && __has_include(<CrashReporterClient.h>)
|
|
|
|
#define HAVE_CRASHREPORTERCLIENT_H 1
|
|
|
|
#include <CrashReporterClient.h>
|
|
|
|
#else
|
|
|
|
#define HAVE_CRASHREPORTERCLIENT_H 0
|
|
|
|
#endif
|
|
|
|
|
2015-12-03 10:39:43 +00:00
|
|
|
#if !SANITIZER_IOS
|
|
|
|
#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
|
|
|
|
#else
|
|
|
|
extern "C" {
|
|
|
|
extern char ***_NSGetArgv(void);
|
|
|
|
}
|
|
|
|
#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-20 18:41:44 +00:00
|
|
|
#include <asl.h>
|
2015-12-03 10:39:43 +00:00
|
|
|
#include <dlfcn.h> // for dladdr()
|
2015-05-12 20:47:21 +00:00
|
|
|
#include <errno.h>
|
2012-06-07 07:13:46 +00:00
|
|
|
#include <fcntl.h>
|
2015-05-12 20:47:21 +00:00
|
|
|
#include <libkern/OSAtomic.h>
|
2015-02-27 03:12:19 +00:00
|
|
|
#include <mach-o/dyld.h>
|
2015-05-12 20:47:21 +00:00
|
|
|
#include <mach/mach.h>
|
2018-02-11 19:25:34 +00:00
|
|
|
#include <mach/mach_time.h>
|
2015-10-27 20:12:53 +00:00
|
|
|
#include <mach/vm_statistics.h>
|
2018-03-24 07:45:24 +00:00
|
|
|
#include <malloc/malloc.h>
|
2021-02-04 21:03:25 -08:00
|
|
|
#include <os/log.h>
|
2012-06-07 07:13:46 +00:00
|
|
|
#include <pthread.h>
|
2022-07-22 11:33:35 -07:00
|
|
|
#include <pthread/introspection.h>
|
2012-06-18 08:44:30 +00:00
|
|
|
#include <sched.h>
|
2014-01-31 13:10:07 +00:00
|
|
|
#include <signal.h>
|
2019-08-15 00:18:55 +00:00
|
|
|
#include <spawn.h>
|
2015-02-27 03:12:19 +00:00
|
|
|
#include <stdlib.h>
|
2019-08-15 00:18:55 +00:00
|
|
|
#include <sys/ioctl.h>
|
2012-06-04 14:27:50 +00:00
|
|
|
#include <sys/mman.h>
|
2012-06-07 07:13:46 +00:00
|
|
|
#include <sys/resource.h>
|
2012-06-05 07:05:10 +00:00
|
|
|
#include <sys/stat.h>
|
2014-02-03 15:32:19 +00:00
|
|
|
#include <sys/sysctl.h>
|
2012-06-05 07:05:10 +00:00
|
|
|
#include <sys/types.h>
|
2016-01-26 22:53:52 +00:00
|
|
|
#include <sys/wait.h>
|
2012-06-05 08:32:53 +00:00
|
|
|
#include <unistd.h>
|
2015-11-20 14:28:33 +00:00
|
|
|
#include <util.h>
|
2012-06-04 14:27:50 +00:00
|
|
|
|
2016-10-05 20:33:59 +00:00
|
|
|
// From <crt_externs.h>, but we don't have that file on iOS.
|
2016-02-02 02:01:17 +00:00
|
|
|
extern "C" {
|
|
|
|
extern char ***_NSGetArgv(void);
|
|
|
|
extern char ***_NSGetEnviron(void);
|
|
|
|
}
|
|
|
|
|
2016-10-05 20:33:59 +00:00
|
|
|
// From <mach/mach_vm.h>, but we don't have that file on iOS.
|
|
|
|
extern "C" {
|
2016-10-05 20:45:34 +00:00
|
|
|
extern kern_return_t mach_vm_region_recurse(
|
2016-10-05 20:33:59 +00:00
|
|
|
vm_map_t target_task,
|
|
|
|
mach_vm_address_t *address,
|
|
|
|
mach_vm_size_t *size,
|
|
|
|
natural_t *nesting_depth,
|
|
|
|
vm_region_recurse_info_t info,
|
|
|
|
mach_msg_type_number_t *infoCnt);
|
|
|
|
}
|
|
|
|
|
2012-06-04 14:27:50 +00:00
|
|
|
namespace __sanitizer {
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
#include "sanitizer_syscall_generic.inc"
|
|
|
|
|
2017-02-03 06:58:14 +00:00
|
|
|
// Direct syscalls, don't call libmalloc hooks (but not available on 10.6).
|
2016-03-24 11:50:21 +00:00
|
|
|
extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,
|
2017-02-03 06:58:14 +00:00
|
|
|
off_t off) SANITIZER_WEAK_ATTRIBUTE;
|
|
|
|
extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE;
|
2016-03-24 11:50:21 +00:00
|
|
|
|
2012-06-07 07:13:46 +00:00
|
|
|
// ---------------------- sanitizer_libc.h
|
2018-07-20 17:07:35 +00:00
|
|
|
|
|
|
|
// From <mach/vm_statistics.h>, but not on older OSs.
|
|
|
|
#ifndef VM_MEMORY_SANITIZER
|
|
|
|
#define VM_MEMORY_SANITIZER 99
|
|
|
|
#endif
|
|
|
|
|
2018-11-06 19:55:19 +00:00
|
|
|
// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of
|
|
|
|
// giant memory regions (i.e. shadow memory regions).
|
|
|
|
#define kXnuFastMmapFd 0x4
|
|
|
|
static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB
|
|
|
|
static bool use_xnu_fast_mmap = false;
|
|
|
|
|
2013-05-08 15:07:12 +00:00
|
|
|
uptr internal_mmap(void *addr, size_t length, int prot, int flags,
|
|
|
|
int fd, u64 offset) {
|
2018-11-06 19:55:19 +00:00
|
|
|
if (fd == -1) {
|
|
|
|
fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER);
|
|
|
|
if (length >= kXnuFastMmapThreshold) {
|
|
|
|
if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd;
|
|
|
|
}
|
|
|
|
}
|
2017-03-24 03:57:27 +00:00
|
|
|
if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset);
|
2017-02-03 06:58:14 +00:00
|
|
|
return (uptr)mmap(addr, length, prot, flags, fd, offset);
|
2012-06-04 14:27:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 15:07:12 +00:00
|
|
|
uptr internal_munmap(void *addr, uptr length) {
|
2017-03-24 03:57:27 +00:00
|
|
|
if (&__munmap) return __munmap(addr, length);
|
2017-02-03 06:58:14 +00:00
|
|
|
return munmap(addr, length);
|
2012-06-05 09:49:25 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 11:21:08 -07:00
|
|
|
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
|
|
|
|
void *new_address) {
|
|
|
|
CHECK(false && "internal_mremap is unimplemented on Mac");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-10 15:02:19 +00:00
|
|
|
int internal_mprotect(void *addr, uptr length, int prot) {
|
|
|
|
return mprotect(addr, length, prot);
|
|
|
|
}
|
|
|
|
|
2020-08-12 19:32:15 -07:00
|
|
|
int internal_madvise(uptr addr, uptr length, int advice) {
|
|
|
|
return madvise((void *)addr, length, advice);
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_close(fd_t fd) {
|
2012-06-05 08:32:53 +00:00
|
|
|
return close(fd);
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_open(const char *filename, int flags) {
|
2013-02-01 15:58:46 +00:00
|
|
|
return open(filename, flags);
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_open(const char *filename, int flags, u32 mode) {
|
2013-02-01 15:58:46 +00:00
|
|
|
return open(filename, flags, mode);
|
|
|
|
}
|
|
|
|
|
2012-06-05 08:32:53 +00: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 14:43:49 +00:00
|
|
|
uptr internal_stat(const char *path, void *buf) {
|
2013-02-04 10:31:39 +00:00
|
|
|
return stat(path, (struct stat *)buf);
|
2013-02-04 10:16:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_lstat(const char *path, void *buf) {
|
2013-02-04 10:31:39 +00:00
|
|
|
return lstat(path, (struct stat *)buf);
|
2013-02-04 10:16:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_fstat(fd_t fd, void *buf) {
|
2013-02-04 10:31:39 +00:00
|
|
|
return fstat(fd, (struct stat *)buf);
|
2013-02-04 10:16:50 +00:00
|
|
|
}
|
|
|
|
|
2012-06-06 07:30:33 +00:00
|
|
|
uptr internal_filesize(fd_t fd) {
|
2012-08-02 10:09:31 +00:00
|
|
|
struct stat st;
|
2013-02-04 10:16:50 +00:00
|
|
|
if (internal_fstat(fd, &st))
|
2012-06-06 07:30:33 +00:00
|
|
|
return -1;
|
|
|
|
return (uptr)st.st_size;
|
|
|
|
}
|
|
|
|
|
2018-12-20 20:36:33 +00:00
|
|
|
uptr internal_dup(int oldfd) {
|
|
|
|
return dup(oldfd);
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_dup2(int oldfd, int newfd) {
|
2012-06-06 07:30:33 +00:00
|
|
|
return dup2(oldfd, newfd);
|
|
|
|
}
|
|
|
|
|
2012-09-05 14:48:24 +00:00
|
|
|
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
|
|
|
return readlink(path, buf, bufsize);
|
|
|
|
}
|
|
|
|
|
2014-12-29 02:18:59 +00:00
|
|
|
uptr internal_unlink(const char *path) {
|
|
|
|
return unlink(path);
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_sched_yield() {
|
2012-06-18 08:44:30 +00:00
|
|
|
return sched_yield();
|
|
|
|
}
|
|
|
|
|
2013-02-20 13:54:32 +00:00
|
|
|
void internal__exit(int exitcode) {
|
|
|
|
_exit(exitcode);
|
|
|
|
}
|
|
|
|
|
2021-07-09 20:21:52 +02:00
|
|
|
void internal_usleep(u64 useconds) { usleep(useconds); }
|
2016-05-12 14:08:56 +00:00
|
|
|
|
2013-05-17 16:56:53 +00:00
|
|
|
uptr internal_getpid() {
|
|
|
|
return getpid();
|
|
|
|
}
|
|
|
|
|
[Sanitizers] Get link map on FreeBSD and NetBSD via documented API
Summary:
Instead of hand-crafting an offset into the structure returned by
dlopen(3) to get at the link map, use the documented API. This is
described in dlinfo(3): by calling it with `RTLD_DI_LINKMAP`, the
dynamic linker ensures the right address is returned.
This is a recommit of 92e267a94dc4272511be674062f8a3e8897b7083, with
dlinfo(3) expliclity being referenced only for FreeBSD, non-Android
Linux, NetBSD and Solaris. Other OSes will have to add their own
implementation.
Reviewers: devnexen, emaste, MaskRay, krytarowski
Reviewed By: krytarowski
Subscribers: krytarowski, vitalybuka, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73990
2020-02-10 23:43:12 +01:00
|
|
|
int internal_dlinfo(void *handle, int request, void *p) {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
2014-01-31 13:10:07 +00:00
|
|
|
int internal_sigaction(int signum, const void *act, void *oldact) {
|
|
|
|
return sigaction(signum,
|
2017-11-10 03:13:42 +00:00
|
|
|
(const struct sigaction *)act, (struct sigaction *)oldact);
|
2014-01-31 13:10:07 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 20:56:44 +00:00
|
|
|
void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }
|
|
|
|
|
|
|
|
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
|
|
|
|
__sanitizer_sigset_t *oldset) {
|
2017-07-05 22:17:44 +00:00
|
|
|
// Don't use sigprocmask here, because it affects all threads.
|
|
|
|
return pthread_sigmask(how, set, oldset);
|
2015-05-12 20:56:44 +00:00
|
|
|
}
|
|
|
|
|
2017-02-03 06:58:14 +00:00
|
|
|
// Doesn't call pthread_atfork() handlers (but not available on 10.6).
|
|
|
|
extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE;
|
2015-11-20 14:28:33 +00:00
|
|
|
|
2014-05-13 16:17:54 +00:00
|
|
|
int internal_fork() {
|
2017-03-24 03:57:27 +00:00
|
|
|
if (&__fork)
|
2017-02-03 06:58:14 +00:00
|
|
|
return __fork();
|
|
|
|
return fork();
|
2015-11-20 14:28:33 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 08:10:06 +00:00
|
|
|
int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
|
|
|
|
uptr *oldlenp, const void *newp, uptr newlen) {
|
2018-10-01 16:51:01 +00:00
|
|
|
return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp,
|
|
|
|
const_cast<void *>(newp), (size_t)newlen);
|
2018-08-31 08:10:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 06:58:02 +00:00
|
|
|
int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
|
|
|
|
const void *newp, uptr newlen) {
|
|
|
|
return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp),
|
|
|
|
(size_t)newlen);
|
|
|
|
}
|
|
|
|
|
2020-03-23 19:57:33 -07:00
|
|
|
static fd_t internal_spawn_impl(const char *argv[], const char *envp[],
|
|
|
|
pid_t *pid) {
|
2021-11-19 11:00:14 -06:00
|
|
|
fd_t primary_fd = kInvalidFd;
|
|
|
|
fd_t secondary_fd = kInvalidFd;
|
2019-08-15 00:18:55 +00:00
|
|
|
|
|
|
|
auto fd_closer = at_scope_exit([&] {
|
2021-11-19 11:00:14 -06:00
|
|
|
internal_close(primary_fd);
|
|
|
|
internal_close(secondary_fd);
|
2019-08-15 00:18:55 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// We need a new pseudoterminal to avoid buffering problems. The 'atos' tool
|
|
|
|
// in particular detects when it's talking to a pipe and forgets to flush the
|
|
|
|
// output stream after sending a response.
|
2021-11-19 11:00:14 -06:00
|
|
|
primary_fd = posix_openpt(O_RDWR);
|
|
|
|
if (primary_fd == kInvalidFd)
|
|
|
|
return kInvalidFd;
|
2019-08-15 00:18:55 +00:00
|
|
|
|
2021-11-19 11:00:14 -06:00
|
|
|
int res = grantpt(primary_fd) || unlockpt(primary_fd);
|
2019-08-15 00:18:55 +00:00
|
|
|
if (res != 0) return kInvalidFd;
|
|
|
|
|
|
|
|
// Use TIOCPTYGNAME instead of ptsname() to avoid threading problems.
|
2021-11-19 11:00:14 -06:00
|
|
|
char secondary_pty_name[128];
|
|
|
|
res = ioctl(primary_fd, TIOCPTYGNAME, secondary_pty_name);
|
2019-08-15 00:18:55 +00:00
|
|
|
if (res == -1) return kInvalidFd;
|
|
|
|
|
2021-11-19 11:00:14 -06:00
|
|
|
secondary_fd = internal_open(secondary_pty_name, O_RDWR);
|
|
|
|
if (secondary_fd == kInvalidFd)
|
|
|
|
return kInvalidFd;
|
2019-08-15 00:18:55 +00:00
|
|
|
|
2019-08-27 22:12:26 +00:00
|
|
|
// File descriptor actions
|
2019-08-15 00:18:55 +00:00
|
|
|
posix_spawn_file_actions_t acts;
|
|
|
|
res = posix_spawn_file_actions_init(&acts);
|
|
|
|
if (res != 0) return kInvalidFd;
|
|
|
|
|
2019-08-27 22:12:26 +00:00
|
|
|
auto acts_cleanup = at_scope_exit([&] {
|
2019-08-15 00:18:55 +00:00
|
|
|
posix_spawn_file_actions_destroy(&acts);
|
|
|
|
});
|
|
|
|
|
2021-11-19 11:00:14 -06:00
|
|
|
res = posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDIN_FILENO) ||
|
|
|
|
posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDOUT_FILENO) ||
|
|
|
|
posix_spawn_file_actions_addclose(&acts, secondary_fd);
|
2019-08-27 22:12:26 +00:00
|
|
|
if (res != 0) return kInvalidFd;
|
|
|
|
|
|
|
|
// Spawn attributes
|
|
|
|
posix_spawnattr_t attrs;
|
|
|
|
res = posix_spawnattr_init(&attrs);
|
|
|
|
if (res != 0) return kInvalidFd;
|
|
|
|
|
|
|
|
auto attrs_cleanup = at_scope_exit([&] {
|
|
|
|
posix_spawnattr_destroy(&attrs);
|
|
|
|
});
|
|
|
|
|
|
|
|
// In the spawned process, close all file descriptors that are not explicitly
|
|
|
|
// described by the file actions object. This is Darwin-specific extension.
|
|
|
|
res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT);
|
|
|
|
if (res != 0) return kInvalidFd;
|
|
|
|
|
|
|
|
// posix_spawn
|
|
|
|
char **argv_casted = const_cast<char **>(argv);
|
2020-03-23 19:57:33 -07:00
|
|
|
char **envp_casted = const_cast<char **>(envp);
|
|
|
|
res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);
|
2019-08-15 00:18:55 +00:00
|
|
|
if (res != 0) return kInvalidFd;
|
|
|
|
|
|
|
|
// Disable echo in the new terminal, disable CR.
|
|
|
|
struct termios termflags;
|
2021-11-19 11:00:14 -06:00
|
|
|
tcgetattr(primary_fd, &termflags);
|
2019-08-15 00:18:55 +00:00
|
|
|
termflags.c_oflag &= ~ONLCR;
|
|
|
|
termflags.c_lflag &= ~ECHO;
|
2021-11-19 11:00:14 -06:00
|
|
|
tcsetattr(primary_fd, TCSANOW, &termflags);
|
2019-08-15 00:18:55 +00:00
|
|
|
|
2021-11-19 11:00:14 -06:00
|
|
|
// On success, do not close primary_fd on scope exit.
|
|
|
|
fd_t fd = primary_fd;
|
|
|
|
primary_fd = kInvalidFd;
|
2019-08-15 00:18:55 +00:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2020-03-23 19:57:33 -07:00
|
|
|
fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {
|
2019-08-15 00:18:55 +00:00
|
|
|
// The client program may close its stdin and/or stdout and/or stderr thus
|
|
|
|
// allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this
|
|
|
|
// case the communication is broken if either the parent or the child tries to
|
|
|
|
// close or duplicate these descriptors. We temporarily reserve these
|
|
|
|
// descriptors here to prevent this.
|
|
|
|
fd_t low_fds[3];
|
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
for (; count < 3; count++) {
|
|
|
|
low_fds[count] = posix_openpt(O_RDWR);
|
|
|
|
if (low_fds[count] >= STDERR_FILENO)
|
|
|
|
break;
|
2018-02-11 20:44:04 +00:00
|
|
|
}
|
2019-08-15 00:18:55 +00:00
|
|
|
|
2020-03-23 19:57:33 -07:00
|
|
|
fd_t fd = internal_spawn_impl(argv, envp, pid);
|
2019-08-15 00:18:55 +00:00
|
|
|
|
|
|
|
for (; count > 0; count--) {
|
|
|
|
internal_close(low_fds[count]);
|
2018-02-11 20:44:04 +00:00
|
|
|
}
|
2019-08-15 00:18:55 +00:00
|
|
|
|
|
|
|
return fd;
|
2014-05-13 16:17:54 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 12:37:52 +00: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);
|
|
|
|
}
|
|
|
|
|
2016-01-26 22:53:52 +00:00
|
|
|
uptr internal_execve(const char *filename, char *const argv[],
|
|
|
|
char *const envp[]) {
|
|
|
|
return execve(filename, argv, envp);
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_waitpid(int pid, int *status, int options) {
|
|
|
|
return waitpid(pid, status, options);
|
|
|
|
}
|
|
|
|
|
2012-06-07 07:13:46 +00:00
|
|
|
// ----------------- sanitizer_common.h
|
2012-11-09 14:45:30 +00:00
|
|
|
bool FileExists(const char *filename) {
|
2019-01-08 01:07:34 +00:00
|
|
|
if (ShouldMockFailureToOpen(filename))
|
|
|
|
return false;
|
2012-11-09 14:45:30 +00:00
|
|
|
struct stat st;
|
|
|
|
if (stat(filename, &st))
|
|
|
|
return false;
|
|
|
|
// Sanity check: filename is a regular file.
|
|
|
|
return S_ISREG(st.st_mode);
|
|
|
|
}
|
|
|
|
|
2022-02-10 15:42:38 -08:00
|
|
|
bool DirExists(const char *path) {
|
|
|
|
struct stat st;
|
|
|
|
if (stat(path, &st))
|
|
|
|
return false;
|
|
|
|
return S_ISDIR(st.st_mode);
|
|
|
|
}
|
|
|
|
|
2017-04-17 18:17:38 +00:00
|
|
|
tid_t GetTid() {
|
|
|
|
tid_t tid;
|
2016-04-21 14:38:41 +00:00
|
|
|
pthread_threadid_np(nullptr, &tid);
|
|
|
|
return tid;
|
2012-10-02 12:58:14 +00:00
|
|
|
}
|
|
|
|
|
2012-06-07 07:32:00 +00:00
|
|
|
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
2012-06-07 07:13:46 +00:00
|
|
|
uptr *stack_bottom) {
|
|
|
|
CHECK(stack_top);
|
|
|
|
CHECK(stack_bottom);
|
|
|
|
uptr stacksize = pthread_get_stacksize_np(pthread_self());
|
2014-02-03 16:42:29 +00:00
|
|
|
// pthread_get_stacksize_np() returns an incorrect stack size for the main
|
|
|
|
// thread on Mavericks. See
|
2015-12-04 17:50:03 +00:00
|
|
|
// https://github.com/google/sanitizers/issues/261
|
2020-05-14 14:52:35 -07:00
|
|
|
if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization &&
|
2014-02-03 16:42:29 +00: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 07:13:46 +00:00
|
|
|
void *stackaddr = pthread_get_stackaddr_np(pthread_self());
|
|
|
|
*stack_top = (uptr)stackaddr;
|
2012-06-07 07:32:00 +00:00
|
|
|
*stack_bottom = *stack_top - stacksize;
|
2012-06-07 07:13:46 +00:00
|
|
|
}
|
|
|
|
|
2015-06-23 21:39:49 +00:00
|
|
|
char **GetEnviron() {
|
|
|
|
#if !SANITIZER_IOS
|
2012-06-14 14:07:21 +00:00
|
|
|
char ***env_ptr = _NSGetEnviron();
|
2013-11-13 13:34:53 +00: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 14:07:21 +00:00
|
|
|
char **environ = *env_ptr;
|
2015-06-23 21:39:49 +00:00
|
|
|
#endif
|
2012-06-14 14:07:21 +00:00
|
|
|
CHECK(environ);
|
2015-06-23 21:39:49 +00:00
|
|
|
return environ;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *GetEnv(const char *name) {
|
|
|
|
char **env = GetEnviron();
|
2012-06-14 14:07:21 +00:00
|
|
|
uptr name_len = internal_strlen(name);
|
2015-06-23 21:39:49 +00:00
|
|
|
while (*env != 0) {
|
|
|
|
uptr len = internal_strlen(*env);
|
2012-06-14 14:07:21 +00:00
|
|
|
if (len > name_len) {
|
2015-06-23 21:39:49 +00:00
|
|
|
const char *p = *env;
|
2012-06-14 14:07:21 +00:00
|
|
|
if (!internal_memcmp(p, name, name_len) &&
|
|
|
|
p[name_len] == '=') { // Match.
|
2015-06-23 21:39:49 +00:00
|
|
|
return *env + name_len + 1; // String starting after =.
|
2012-06-14 14:07:21 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-23 21:39:49 +00:00
|
|
|
env++;
|
2012-06-14 14:07:21 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2012-06-07 07:13:46 +00:00
|
|
|
|
2015-02-27 03:12:19 +00: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.
|
2021-03-16 04:03:45 -07:00
|
|
|
InternalMmapVector<char> exe_path(kMaxPathLength);
|
2015-02-27 03:12:19 +00:00
|
|
|
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-28 21:01:42 +00:00
|
|
|
uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
|
|
|
|
return ReadBinaryName(buf, buf_len);
|
|
|
|
}
|
|
|
|
|
2012-09-17 09:12:39 +00:00
|
|
|
void ReExec() {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
2018-06-05 07:29:23 +00:00
|
|
|
void CheckASLR() {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
|
2018-12-23 15:09:28 +00:00
|
|
|
void CheckMPROTECT() {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
|
2013-05-20 17:05:29 +00:00
|
|
|
uptr GetPageSize() {
|
|
|
|
return sysconf(_SC_PAGESIZE);
|
|
|
|
}
|
|
|
|
|
2018-03-24 08:13:18 +00:00
|
|
|
extern "C" unsigned malloc_num_zones;
|
|
|
|
extern "C" malloc_zone_t **malloc_zones;
|
|
|
|
malloc_zone_t sanitizer_zone;
|
2018-03-24 07:45:24 +00:00
|
|
|
|
|
|
|
// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If
|
|
|
|
// libmalloc tries to set up a different zone as malloc_zones[0], it will call
|
|
|
|
// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and
|
|
|
|
// make sure we are still the first (default) zone.
|
|
|
|
void MprotectMallocZones(void *addr, int prot) {
|
|
|
|
if (addr == malloc_zones && prot == PROT_READ) {
|
|
|
|
if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) {
|
|
|
|
for (unsigned i = 1; i < malloc_num_zones; i++) {
|
|
|
|
if (malloc_zones[i] == &sanitizer_zone) {
|
|
|
|
// Swap malloc_zones[0] and malloc_zones[i].
|
|
|
|
malloc_zones[i] = malloc_zones[0];
|
|
|
|
malloc_zones[0] = &sanitizer_zone;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-15 17:15:48 +02:00
|
|
|
void FutexWait(atomic_uint32_t *p, u32 cmp) {
|
|
|
|
// FIXME: implement actual blocking.
|
|
|
|
sched_yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FutexWake(atomic_uint32_t *p, u32 count) {}
|
|
|
|
|
2013-06-06 13:00:32 +00:00
|
|
|
u64 NanoTime() {
|
2018-02-11 19:25:34 +00:00
|
|
|
timeval tv;
|
|
|
|
internal_memset(&tv, 0, sizeof(tv));
|
|
|
|
gettimeofday(&tv, 0);
|
|
|
|
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
|
2013-06-06 13:00:32 +00:00
|
|
|
}
|
|
|
|
|
2018-02-11 19:25:34 +00:00
|
|
|
// This needs to be called during initialization to avoid being racy.
|
2017-12-13 16:23:54 +00:00
|
|
|
u64 MonotonicNanoTime() {
|
2018-02-11 19:25:34 +00:00
|
|
|
static mach_timebase_info_data_t timebase_info;
|
|
|
|
if (timebase_info.denom == 0) mach_timebase_info(&timebase_info);
|
|
|
|
return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom;
|
2017-12-13 16:23:54 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 08:19:53 +00:00
|
|
|
uptr GetTlsSize() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-05 19:00:18 -04:00
|
|
|
void InitTlsSize() {
|
|
|
|
}
|
|
|
|
|
Implement tls scanning for darwin LSan
Summary:
This required for any users who call exit() after creating
thread-specific data, as tls destructors are only called when
pthread_exit() or pthread_cancel() are used. This should also
match tls behavior on linux.
Getting the base address of the tls section is straightforward,
as it's stored as a section offset in %gs. The size is a bit trickier
to work out, as there doesn't appear to be any official documentation
or source code referring to it. The size used in this patch was determined
by taking the difference between the base address and the address of the
subsequent memory region returned by vm_region_recurse_64, which was
1024 * sizeof(uptr) on all threads except the main thread, where it was
larger. Since the section must be the same size on all of the threads,
1024 * sizeof(uptr) seemed to be a reasonable size to use, barring
a more programtic way to get the size.
1024 seems like a reasonable number, given that PTHREAD_KEYS_MAX
is 512 on darwin, so pthread keys will fit inside the region while
leaving space for other tls data. A larger size would overflow the
memory region returned by vm_region_recurse_64, and a smaller size
wouldn't leave room for all the pthread keys. In addition, the
stress test added here passes, which means that we are scanning at
least the full set of possible pthread keys, and probably
the full tls section.
Reviewers: alekseyshl, kubamracek
Subscribers: krytarowski, llvm-commits
Differential Revision: https://reviews.llvm.org/D33215
llvm-svn: 303887
2017-05-25 17:41:13 +00:00
|
|
|
uptr TlsBaseAddr() {
|
|
|
|
uptr segbase = 0;
|
|
|
|
#if defined(__x86_64__)
|
|
|
|
asm("movq %%gs:0,%0" : "=r"(segbase));
|
|
|
|
#elif defined(__i386__)
|
|
|
|
asm("movl %%gs:0,%0" : "=r"(segbase));
|
2021-11-08 22:26:32 +00:00
|
|
|
#elif defined(__aarch64__)
|
|
|
|
asm("mrs %x0, tpidrro_el0" : "=r"(segbase));
|
|
|
|
segbase &= 0x07ul; // clearing lower bits, cpu id stored there
|
Implement tls scanning for darwin LSan
Summary:
This required for any users who call exit() after creating
thread-specific data, as tls destructors are only called when
pthread_exit() or pthread_cancel() are used. This should also
match tls behavior on linux.
Getting the base address of the tls section is straightforward,
as it's stored as a section offset in %gs. The size is a bit trickier
to work out, as there doesn't appear to be any official documentation
or source code referring to it. The size used in this patch was determined
by taking the difference between the base address and the address of the
subsequent memory region returned by vm_region_recurse_64, which was
1024 * sizeof(uptr) on all threads except the main thread, where it was
larger. Since the section must be the same size on all of the threads,
1024 * sizeof(uptr) seemed to be a reasonable size to use, barring
a more programtic way to get the size.
1024 seems like a reasonable number, given that PTHREAD_KEYS_MAX
is 512 on darwin, so pthread keys will fit inside the region while
leaving space for other tls data. A larger size would overflow the
memory region returned by vm_region_recurse_64, and a smaller size
wouldn't leave room for all the pthread keys. In addition, the
stress test added here passes, which means that we are scanning at
least the full set of possible pthread keys, and probably
the full tls section.
Reviewers: alekseyshl, kubamracek
Subscribers: krytarowski, llvm-commits
Differential Revision: https://reviews.llvm.org/D33215
llvm-svn: 303887
2017-05-25 17:41:13 +00:00
|
|
|
#endif
|
|
|
|
return segbase;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The size of the tls on darwin does not appear to be well documented,
|
|
|
|
// however the vm memory map suggests that it is 1024 uptrs in size,
|
|
|
|
// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386.
|
|
|
|
uptr TlsSize() {
|
|
|
|
#if defined(__x86_64__) || defined(__i386__)
|
|
|
|
return 1024 * sizeof(uptr);
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-07 14:41:43 +00:00
|
|
|
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
|
|
|
uptr *tls_addr, uptr *tls_size) {
|
2016-10-28 20:14:18 +00:00
|
|
|
#if !SANITIZER_GO
|
2013-05-07 14:41:43 +00:00
|
|
|
uptr stack_top, stack_bottom;
|
|
|
|
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
|
|
|
|
*stk_addr = stack_bottom;
|
|
|
|
*stk_size = stack_top - stack_bottom;
|
Implement tls scanning for darwin LSan
Summary:
This required for any users who call exit() after creating
thread-specific data, as tls destructors are only called when
pthread_exit() or pthread_cancel() are used. This should also
match tls behavior on linux.
Getting the base address of the tls section is straightforward,
as it's stored as a section offset in %gs. The size is a bit trickier
to work out, as there doesn't appear to be any official documentation
or source code referring to it. The size used in this patch was determined
by taking the difference between the base address and the address of the
subsequent memory region returned by vm_region_recurse_64, which was
1024 * sizeof(uptr) on all threads except the main thread, where it was
larger. Since the section must be the same size on all of the threads,
1024 * sizeof(uptr) seemed to be a reasonable size to use, barring
a more programtic way to get the size.
1024 seems like a reasonable number, given that PTHREAD_KEYS_MAX
is 512 on darwin, so pthread keys will fit inside the region while
leaving space for other tls data. A larger size would overflow the
memory region returned by vm_region_recurse_64, and a smaller size
wouldn't leave room for all the pthread keys. In addition, the
stress test added here passes, which means that we are scanning at
least the full set of possible pthread keys, and probably
the full tls section.
Reviewers: alekseyshl, kubamracek
Subscribers: krytarowski, llvm-commits
Differential Revision: https://reviews.llvm.org/D33215
llvm-svn: 303887
2017-05-25 17:41:13 +00:00
|
|
|
*tls_addr = TlsBaseAddr();
|
|
|
|
*tls_size = TlsSize();
|
2013-06-06 13:20:40 +00:00
|
|
|
#else
|
|
|
|
*stk_addr = 0;
|
|
|
|
*stk_size = 0;
|
|
|
|
*tls_addr = 0;
|
|
|
|
*tls_size = 0;
|
|
|
|
#endif
|
2013-05-07 14:41:43 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 18:52:51 +00:00
|
|
|
void ListOfModules::init() {
|
2017-09-29 20:55:06 +00:00
|
|
|
clearOrInit();
|
2013-09-10 14:36:16 +00:00
|
|
|
MemoryMappingLayout memory_mapping(false);
|
2016-02-22 18:52:51 +00:00
|
|
|
memory_mapping.DumpListOfModules(&modules_);
|
2013-09-10 14:36:16 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 20:22:16 +00:00
|
|
|
void ListOfModules::fallbackInit() { clear(); }
|
|
|
|
|
2017-06-15 00:19:13 +00:00
|
|
|
static HandleSignalMode GetHandleSignalModeImpl(int signum) {
|
2017-05-18 23:13:22 +00:00
|
|
|
switch (signum) {
|
|
|
|
case SIGABRT:
|
|
|
|
return common_flags()->handle_abort;
|
|
|
|
case SIGILL:
|
|
|
|
return common_flags()->handle_sigill;
|
2018-02-21 19:52:23 +00:00
|
|
|
case SIGTRAP:
|
|
|
|
return common_flags()->handle_sigtrap;
|
2017-05-18 23:13:22 +00:00
|
|
|
case SIGFPE:
|
|
|
|
return common_flags()->handle_sigfpe;
|
|
|
|
case SIGSEGV:
|
|
|
|
return common_flags()->handle_segv;
|
|
|
|
case SIGBUS:
|
|
|
|
return common_flags()->handle_sigbus;
|
|
|
|
}
|
2017-05-25 23:42:33 +00:00
|
|
|
return kHandleSignalNo;
|
2014-01-31 13:10:07 +00:00
|
|
|
}
|
|
|
|
|
2017-06-15 00:19:13 +00:00
|
|
|
HandleSignalMode GetHandleSignalMode(int signum) {
|
|
|
|
// Handling fatal signals on watchOS and tvOS devices is disallowed.
|
|
|
|
if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))
|
|
|
|
return kHandleSignalNo;
|
|
|
|
HandleSignalMode result = GetHandleSignalModeImpl(signum);
|
|
|
|
if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)
|
|
|
|
return kHandleSignalExclusive;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-07-29 12:50:49 -07:00
|
|
|
// Offset example:
|
|
|
|
// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4
|
|
|
|
constexpr u16 GetOSMajorKernelOffset() {
|
|
|
|
if (TARGET_OS_OSX) return 4;
|
2020-07-31 11:38:10 -07:00
|
|
|
if (TARGET_OS_IOS || TARGET_OS_TV) return 6;
|
|
|
|
if (TARGET_OS_WATCH) return 13;
|
2020-07-29 12:50:49 -07:00
|
|
|
}
|
|
|
|
|
2020-07-24 11:24:34 -07:00
|
|
|
using VersStr = char[64];
|
|
|
|
|
2021-01-06 12:41:40 -08:00
|
|
|
static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
|
|
|
|
u16 kernel_major = GetDarwinKernelVersion().major;
|
|
|
|
u16 offset = GetOSMajorKernelOffset();
|
|
|
|
CHECK_GE(kernel_major, offset);
|
|
|
|
u16 os_major = kernel_major - offset;
|
|
|
|
|
|
|
|
const char *format = "%d.0";
|
|
|
|
if (TARGET_OS_OSX) {
|
|
|
|
if (os_major >= 16) { // macOS 11+
|
|
|
|
os_major -= 5;
|
|
|
|
} else { // macOS 10.15 and below
|
|
|
|
format = "10.%d";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return internal_snprintf(vers, sizeof(VersStr), format, os_major);
|
|
|
|
}
|
|
|
|
|
2020-07-24 11:24:34 -07:00
|
|
|
static void GetOSVersion(VersStr vers) {
|
|
|
|
uptr len = sizeof(VersStr);
|
|
|
|
if (SANITIZER_IOSSIM) {
|
|
|
|
const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION");
|
|
|
|
if (!vers_env) {
|
|
|
|
Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env "
|
|
|
|
"var is not set.\n");
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
len = internal_strlcpy(vers, vers_env, len);
|
2020-06-30 13:19:25 -07:00
|
|
|
} else {
|
2020-07-24 11:24:34 -07:00
|
|
|
int res =
|
|
|
|
internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
|
2021-01-06 12:41:40 -08:00
|
|
|
|
|
|
|
// XNU 17 (macOS 10.13) and below do not provide the sysctl
|
|
|
|
// `kern.osproductversion` entry (res != 0).
|
|
|
|
bool no_os_version = res != 0;
|
|
|
|
|
|
|
|
// For launchd, sanitizer initialization runs before sysctl is setup
|
|
|
|
// (res == 0 && len != strlen(vers), vers is not a valid version). However,
|
|
|
|
// the kernel version `kern.osrelease` is available.
|
|
|
|
bool launchd = (res == 0 && internal_strlen(vers) < 3);
|
|
|
|
if (launchd) CHECK_EQ(internal_getpid(), 1);
|
|
|
|
|
|
|
|
if (no_os_version || launchd) {
|
|
|
|
len = ApproximateOSVersionViaKernelVersion(vers);
|
2020-07-29 12:50:49 -07:00
|
|
|
}
|
2020-07-24 11:24:34 -07:00
|
|
|
}
|
|
|
|
CHECK_LT(len, sizeof(VersStr));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ParseVersion(const char *vers, u16 *major, u16 *minor) {
|
|
|
|
// Format: <major>.<minor>[.<patch>]\0
|
|
|
|
CHECK_GE(internal_strlen(vers), 3);
|
|
|
|
const char *p = vers;
|
|
|
|
*major = internal_simple_strtoll(p, &p, /*base=*/10);
|
|
|
|
CHECK_EQ(*p, '.');
|
|
|
|
p += 1;
|
|
|
|
*minor = internal_simple_strtoll(p, &p, /*base=*/10);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Aligned versions example:
|
|
|
|
// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6
|
|
|
|
static void MapToMacos(u16 *major, u16 *minor) {
|
|
|
|
if (TARGET_OS_OSX)
|
|
|
|
return;
|
|
|
|
|
2020-07-31 11:38:10 -07:00
|
|
|
if (TARGET_OS_IOS || TARGET_OS_TV)
|
2020-07-24 11:24:34 -07:00
|
|
|
*major += 2;
|
2020-07-31 11:38:10 -07:00
|
|
|
else if (TARGET_OS_WATCH)
|
2020-07-24 11:24:34 -07:00
|
|
|
*major += 9;
|
|
|
|
else
|
|
|
|
UNREACHABLE("unsupported platform");
|
|
|
|
|
|
|
|
if (*major >= 16) { // macOS 11+
|
|
|
|
*major -= 5;
|
|
|
|
} else { // macOS 10.15 and below
|
|
|
|
*minor = *major;
|
|
|
|
*major = 10;
|
2020-06-30 13:19:25 -07:00
|
|
|
}
|
2020-07-24 11:24:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static MacosVersion GetMacosAlignedVersionInternal() {
|
2021-01-06 12:41:40 -08:00
|
|
|
VersStr vers = {};
|
2020-07-24 11:24:34 -07:00
|
|
|
GetOSVersion(vers);
|
|
|
|
|
|
|
|
u16 major, minor;
|
|
|
|
ParseVersion(vers, &major, &minor);
|
|
|
|
MapToMacos(&major, &minor);
|
|
|
|
|
2020-06-30 13:19:25 -07:00
|
|
|
return MacosVersion(major, minor);
|
2014-02-03 15:32:19 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:52:35 -07:00
|
|
|
static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type),
|
|
|
|
"MacosVersion cache size");
|
|
|
|
static atomic_uint32_t cached_macos_version;
|
|
|
|
|
|
|
|
MacosVersion GetMacosAlignedVersion() {
|
|
|
|
atomic_uint32_t::Type result =
|
|
|
|
atomic_load(&cached_macos_version, memory_order_acquire);
|
|
|
|
if (!result) {
|
|
|
|
MacosVersion version = GetMacosAlignedVersionInternal();
|
|
|
|
result = *reinterpret_cast<atomic_uint32_t::Type *>(&version);
|
|
|
|
atomic_store(&cached_macos_version, result, memory_order_release);
|
2014-02-03 15:32:19 +00:00
|
|
|
}
|
2020-05-14 14:52:35 -07:00
|
|
|
return *reinterpret_cast<MacosVersion *>(&result);
|
2014-02-03 15:32:19 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 13:43:33 -07:00
|
|
|
DarwinKernelVersion GetDarwinKernelVersion() {
|
2021-01-06 12:41:40 -08:00
|
|
|
VersStr vers = {};
|
2020-07-24 11:24:34 -07:00
|
|
|
uptr len = sizeof(VersStr);
|
|
|
|
int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
|
2020-05-14 13:43:33 -07:00
|
|
|
CHECK_EQ(res, 0);
|
2020-07-24 11:24:34 -07:00
|
|
|
CHECK_LT(len, sizeof(VersStr));
|
2020-05-14 13:43:33 -07:00
|
|
|
|
2020-05-21 11:14:55 -07:00
|
|
|
u16 major, minor;
|
2020-07-24 11:24:34 -07:00
|
|
|
ParseVersion(vers, &major, &minor);
|
2020-05-14 13:43:33 -07:00
|
|
|
|
|
|
|
return DarwinKernelVersion(major, minor);
|
|
|
|
}
|
|
|
|
|
2014-12-09 01:22:59 +00:00
|
|
|
uptr GetRSS() {
|
2015-05-12 20:47:21 +00: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 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 13:01:08 -08:00
|
|
|
void *internal_start_thread(void *(*func)(void *arg), void *arg) {
|
2015-11-11 02:44:19 +00:00
|
|
|
// 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;
|
2020-01-23 13:01:08 -08:00
|
|
|
pthread_create(&th, 0, func, arg);
|
2015-11-11 02:44:19 +00:00
|
|
|
internal_sigprocmask(SIG_SETMASK, &old, 0);
|
|
|
|
return th;
|
|
|
|
}
|
|
|
|
|
|
|
|
void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
|
2014-12-16 19:13:01 +00:00
|
|
|
|
2016-10-28 20:14:18 +00:00
|
|
|
#if !SANITIZER_GO
|
2021-07-28 13:12:24 +02:00
|
|
|
static Mutex syslog_lock;
|
|
|
|
# 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-20 18:41:44 +00:00
|
|
|
|
|
|
|
void WriteOneLineToSyslog(const char *s) {
|
2016-10-28 20:14:18 +00:00
|
|
|
#if !SANITIZER_GO
|
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-20 18:41:44 +00:00
|
|
|
syslog_lock.CheckLocked();
|
2021-02-04 21:03:25 -08:00
|
|
|
if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
|
|
|
|
os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
|
|
|
|
} else {
|
|
|
|
asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
|
|
|
|
}
|
2016-04-27 12:56:16 +00:00
|
|
|
#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-20 18:41:44 +00:00
|
|
|
}
|
|
|
|
|
2021-02-23 09:23:02 -08:00
|
|
|
// buffer to store crash report application information
|
|
|
|
static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
|
2021-07-28 13:12:24 +02:00
|
|
|
static Mutex crashreporter_info_mutex;
|
2021-02-23 09:23:02 -08:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
// Integrate with crash reporter libraries.
|
|
|
|
#if HAVE_CRASHREPORTERCLIENT_H
|
|
|
|
CRASH_REPORTER_CLIENT_HIDDEN
|
|
|
|
struct crashreporter_annotations_t gCRAnnotations
|
|
|
|
__attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
|
|
|
|
CRASHREPORTER_ANNOTATIONS_VERSION,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
#if CRASHREPORTER_ANNOTATIONS_VERSION > 4
|
|
|
|
0,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
#else
|
|
|
|
// fall back to old crashreporter api
|
|
|
|
static const char *__crashreporter_info__ __attribute__((__used__)) =
|
|
|
|
&crashreporter_info_buff[0];
|
|
|
|
asm(".desc ___crashreporter_info__, 0x10");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // extern "C"
|
|
|
|
|
|
|
|
static void CRAppendCrashLogMessage(const char *msg) {
|
2021-07-28 13:12:24 +02:00
|
|
|
Lock l(&crashreporter_info_mutex);
|
2021-02-23 09:23:02 -08:00
|
|
|
internal_strlcat(crashreporter_info_buff, msg,
|
|
|
|
sizeof(crashreporter_info_buff));
|
|
|
|
#if HAVE_CRASHREPORTERCLIENT_H
|
|
|
|
(void)CRSetCrashLogMessage(crashreporter_info_buff);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-01-06 23:15:01 +00:00
|
|
|
void LogMessageOnPrintf(const char *str) {
|
|
|
|
// Log all printf output to CrashLog.
|
|
|
|
if (common_flags()->abort_on_error)
|
|
|
|
CRAppendCrashLogMessage(str);
|
|
|
|
}
|
|
|
|
|
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-20 18:41:44 +00:00
|
|
|
void LogFullErrorReport(const char *buffer) {
|
2016-10-28 20:14:18 +00:00
|
|
|
#if !SANITIZER_GO
|
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-20 18:41:44 +00:00
|
|
|
// Log with os_trace. This will make it into the crash log.
|
|
|
|
#if SANITIZER_OS_TRACE
|
2020-05-14 14:52:35 -07:00
|
|
|
if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) {
|
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-20 18:41:44 +00:00
|
|
|
// 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.
|
2021-07-28 13:12:24 +02:00
|
|
|
Lock l(&syslog_lock);
|
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-20 18:41:44 +00:00
|
|
|
if (common_flags()->log_to_syslog)
|
|
|
|
WriteToSyslog(buffer);
|
2015-11-20 18:42:07 +00:00
|
|
|
|
2016-01-06 23:15:01 +00:00
|
|
|
// The report is added to CrashLog as part of logging all of Printf output.
|
2016-04-27 14:28:42 +00:00
|
|
|
#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-20 18:41:44 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 02:48:41 +00:00
|
|
|
SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
|
2016-04-27 18:02:21 +00:00
|
|
|
#if defined(__x86_64__) || defined(__i386__)
|
|
|
|
ucontext_t *ucontext = static_cast<ucontext_t*>(context);
|
2022-02-02 15:06:01 +01:00
|
|
|
return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? Write : Read;
|
2022-05-11 12:52:32 -07:00
|
|
|
#elif defined(__arm64__)
|
|
|
|
ucontext_t *ucontext = static_cast<ucontext_t*>(context);
|
|
|
|
return ucontext->uc_mcontext->__es.__esr & 0x40 /*ISS_DA_WNR*/ ? Write : Read;
|
2016-04-27 18:02:21 +00:00
|
|
|
#else
|
2022-02-02 15:06:01 +01:00
|
|
|
return Unknown;
|
2016-04-27 18:02:21 +00:00
|
|
|
#endif
|
2016-02-04 02:02:09 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 17:19:58 +00:00
|
|
|
bool SignalContext::IsTrueFaultingAddress() const {
|
|
|
|
auto si = static_cast<const siginfo_t *>(siginfo);
|
|
|
|
// "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero.
|
|
|
|
return si->si_signo == SIGSEGV && si->si_code != 0;
|
|
|
|
}
|
|
|
|
|
2020-04-29 12:55:21 -07:00
|
|
|
#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
|
|
|
|
#define AARCH64_GET_REG(r) \
|
2020-04-29 14:45:25 -07:00
|
|
|
(uptr)ptrauth_strip( \
|
|
|
|
(void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)
|
2020-04-29 12:55:21 -07:00
|
|
|
#else
|
2021-12-17 09:36:16 -05:00
|
|
|
#define AARCH64_GET_REG(r) (uptr)ucontext->uc_mcontext->__ss.__##r
|
2020-04-29 12:55:21 -07:00
|
|
|
#endif
|
|
|
|
|
2017-09-14 02:48:41 +00:00
|
|
|
static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
2015-03-02 17:36:02 +00:00
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
2015-06-23 21:39:49 +00:00
|
|
|
# if defined(__aarch64__)
|
2020-04-29 12:55:21 -07:00
|
|
|
*pc = AARCH64_GET_REG(pc);
|
|
|
|
*bp = AARCH64_GET_REG(fp);
|
|
|
|
*sp = AARCH64_GET_REG(sp);
|
2015-06-23 21:39:49 +00:00
|
|
|
# elif defined(__x86_64__)
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext->__ss.__rip;
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__rbp;
|
|
|
|
*sp = ucontext->uc_mcontext->__ss.__rsp;
|
2015-06-23 21:39:49 +00: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-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext->__ss.__eip;
|
|
|
|
*bp = ucontext->uc_mcontext->__ss.__ebp;
|
|
|
|
*sp = ucontext->uc_mcontext->__ss.__esp;
|
2015-06-23 21:39:49 +00:00
|
|
|
# else
|
|
|
|
# error "Unknown architecture"
|
|
|
|
# endif
|
2015-03-02 17:36:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-29 14:45:25 -07:00
|
|
|
void SignalContext::InitPcSpBp() {
|
|
|
|
addr = (uptr)ptrauth_strip((void *)addr, 0);
|
|
|
|
GetPcSpBp(context, &pc, &sp, &bp);
|
|
|
|
}
|
2017-09-14 02:48:41 +00:00
|
|
|
|
2020-07-29 09:55:52 -07:00
|
|
|
// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers
|
|
|
|
// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).
|
|
|
|
static void DisableMmapExcGuardExceptions() {
|
|
|
|
using task_exc_guard_behavior_t = uint32_t;
|
|
|
|
using task_set_exc_guard_behavior_t =
|
|
|
|
kern_return_t(task_t task, task_exc_guard_behavior_t behavior);
|
|
|
|
auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym(
|
|
|
|
RTLD_DEFAULT, "task_set_exc_guard_behavior");
|
|
|
|
if (set_behavior == nullptr) return;
|
|
|
|
const task_exc_guard_behavior_t task_exc_guard_none = 0;
|
|
|
|
set_behavior(mach_task_self(), task_exc_guard_none);
|
|
|
|
}
|
|
|
|
|
2022-07-01 11:05:40 -07:00
|
|
|
static void VerifyInterceptorsWorking();
|
|
|
|
static void StripEnv();
|
|
|
|
|
2018-11-06 19:55:19 +00:00
|
|
|
void InitializePlatformEarly() {
|
2020-05-14 13:43:33 -07:00
|
|
|
// Only use xnu_fast_mmap when on x86_64 and the kernel supports it.
|
2018-11-06 19:55:19 +00:00
|
|
|
use_xnu_fast_mmap =
|
|
|
|
#if defined(__x86_64__)
|
2020-05-14 13:43:33 -07:00
|
|
|
GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);
|
2018-11-06 19:55:19 +00:00
|
|
|
#else
|
|
|
|
false;
|
|
|
|
#endif
|
2020-07-29 09:55:52 -07:00
|
|
|
if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0))
|
|
|
|
DisableMmapExcGuardExceptions();
|
2022-07-01 11:05:40 -07:00
|
|
|
|
|
|
|
# if !SANITIZER_GO
|
|
|
|
MonotonicNanoTime(); // Call to initialize mach_timebase_info
|
|
|
|
VerifyInterceptorsWorking();
|
|
|
|
StripEnv();
|
|
|
|
# endif
|
2018-11-06 19:55:19 +00:00
|
|
|
}
|
|
|
|
|
2016-10-28 20:14:18 +00:00
|
|
|
#if !SANITIZER_GO
|
2015-12-03 10:39:43 +00:00
|
|
|
static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
|
|
|
|
LowLevelAllocator allocator_for_env;
|
|
|
|
|
2022-07-01 11:05:40 -07:00
|
|
|
static bool ShouldCheckInterceptors() {
|
|
|
|
// Restrict "interceptors working?" check to ASan and TSan.
|
|
|
|
const char *sanitizer_names[] = {"AddressSanitizer", "ThreadSanitizer"};
|
|
|
|
size_t count = sizeof(sanitizer_names) / sizeof(sanitizer_names[0]);
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
if (internal_strcmp(sanitizer_names[i], SanitizerToolName) == 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void VerifyInterceptorsWorking() {
|
|
|
|
if (!common_flags()->verify_interceptors || !ShouldCheckInterceptors())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Verify that interceptors really work. We'll use dlsym to locate
|
|
|
|
// "puts", if interceptors are working, it should really point to
|
|
|
|
// "wrap_puts" within our own dylib.
|
|
|
|
Dl_info info_puts, info_runtime;
|
|
|
|
RAW_CHECK(dladdr(dlsym(RTLD_DEFAULT, "puts"), &info_puts));
|
|
|
|
RAW_CHECK(dladdr((void *)__sanitizer_report_error_summary, &info_runtime));
|
|
|
|
if (internal_strcmp(info_puts.dli_fname, info_runtime.dli_fname) != 0) {
|
|
|
|
Report(
|
|
|
|
"ERROR: Interceptors are not working. This may be because %s is "
|
|
|
|
"loaded too late (e.g. via dlopen). Please launch the executable "
|
|
|
|
"with:\n%s=%s\n",
|
|
|
|
SanitizerToolName, kDyldInsertLibraries, info_runtime.dli_fname);
|
|
|
|
RAW_CHECK("interceptors not installed" && 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:39:43 +00:00
|
|
|
// Change the value of the env var |name|, leaking the original value.
|
|
|
|
// If |name_value| is NULL, the variable is deleted from the environment,
|
|
|
|
// otherwise the corresponding "NAME=value" string is replaced with
|
|
|
|
// |name_value|.
|
2022-07-01 11:05:40 -07:00
|
|
|
static void LeakyResetEnv(const char *name, const char *name_value) {
|
2015-12-03 10:39:43 +00:00
|
|
|
char **env = GetEnviron();
|
|
|
|
uptr name_len = internal_strlen(name);
|
|
|
|
while (*env != 0) {
|
|
|
|
uptr len = internal_strlen(*env);
|
|
|
|
if (len > name_len) {
|
|
|
|
const char *p = *env;
|
|
|
|
if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
|
|
|
|
// Match.
|
|
|
|
if (name_value) {
|
|
|
|
// Replace the old value with the new one.
|
|
|
|
*env = const_cast<char*>(name_value);
|
|
|
|
} else {
|
|
|
|
// Shift the subsequent pointers back.
|
|
|
|
char **del = env;
|
|
|
|
do {
|
|
|
|
del[0] = del[1];
|
|
|
|
} while (*del++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
env++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-01 11:05:40 -07:00
|
|
|
static void StripEnv() {
|
|
|
|
if (!common_flags()->strip_env)
|
|
|
|
return;
|
2015-12-03 10:39:43 +00:00
|
|
|
|
2022-07-01 11:05:40 -07:00
|
|
|
char *dyld_insert_libraries =
|
|
|
|
const_cast<char *>(GetEnv(kDyldInsertLibraries));
|
|
|
|
if (!dyld_insert_libraries)
|
|
|
|
return;
|
2022-07-07 17:26:19 -07:00
|
|
|
|
2015-12-03 10:39:43 +00:00
|
|
|
Dl_info info;
|
2022-07-01 11:05:40 -07:00
|
|
|
RAW_CHECK(dladdr((void *)__sanitizer_report_error_summary, &info));
|
2015-12-03 10:39:43 +00:00
|
|
|
const char *dylib_name = StripModuleName(info.dli_fname);
|
2022-07-01 11:05:40 -07:00
|
|
|
bool lib_is_in_env = internal_strstr(dyld_insert_libraries, dylib_name);
|
2015-12-03 10:39:43 +00:00
|
|
|
if (!lib_is_in_env)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
|
|
|
|
// the dylib from the environment variable, because interceptors are installed
|
|
|
|
// and we don't want our children to inherit the variable.
|
|
|
|
|
2022-07-01 11:05:40 -07:00
|
|
|
uptr old_env_len = internal_strlen(dyld_insert_libraries);
|
|
|
|
uptr dylib_name_len = internal_strlen(dylib_name);
|
2015-12-03 10:39:43 +00:00
|
|
|
uptr env_name_len = internal_strlen(kDyldInsertLibraries);
|
|
|
|
// Allocate memory to hold the previous env var name, its value, the '='
|
|
|
|
// sign and the '\0' char.
|
|
|
|
char *new_env = (char*)allocator_for_env.Allocate(
|
|
|
|
old_env_len + 2 + env_name_len);
|
2016-04-28 09:26:30 +00:00
|
|
|
RAW_CHECK(new_env);
|
2015-12-03 10:39:43 +00:00
|
|
|
internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
|
|
|
|
internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
|
|
|
|
new_env[env_name_len] = '=';
|
|
|
|
char *new_env_pos = new_env + env_name_len + 1;
|
|
|
|
|
|
|
|
// Iterate over colon-separated pieces of |dyld_insert_libraries|.
|
|
|
|
char *piece_start = dyld_insert_libraries;
|
|
|
|
char *piece_end = NULL;
|
|
|
|
char *old_env_end = dyld_insert_libraries + old_env_len;
|
|
|
|
do {
|
|
|
|
if (piece_start[0] == ':') piece_start++;
|
|
|
|
piece_end = internal_strchr(piece_start, ':');
|
|
|
|
if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
|
|
|
|
if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
|
|
|
|
uptr piece_len = piece_end - piece_start;
|
|
|
|
|
|
|
|
char *filename_start =
|
|
|
|
(char *)internal_memrchr(piece_start, '/', piece_len);
|
|
|
|
uptr filename_len = piece_len;
|
|
|
|
if (filename_start) {
|
|
|
|
filename_start += 1;
|
|
|
|
filename_len = piece_len - (filename_start - piece_start);
|
|
|
|
} else {
|
|
|
|
filename_start = piece_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the current piece isn't the runtime library name,
|
|
|
|
// append it to new_env.
|
|
|
|
if ((dylib_name_len != filename_len) ||
|
|
|
|
(internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
|
|
|
|
if (new_env_pos != new_env + env_name_len + 1) {
|
|
|
|
new_env_pos[0] = ':';
|
|
|
|
new_env_pos++;
|
|
|
|
}
|
|
|
|
internal_strncpy(new_env_pos, piece_start, piece_len);
|
|
|
|
new_env_pos += piece_len;
|
|
|
|
}
|
|
|
|
// Move on to the next piece.
|
|
|
|
piece_start = piece_end;
|
|
|
|
} while (piece_start < old_env_end);
|
|
|
|
|
|
|
|
// Can't use setenv() here, because it requires the allocator to be
|
|
|
|
// initialized.
|
|
|
|
// FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
|
|
|
|
// a separate function called after InitializeAllocator().
|
|
|
|
if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
|
|
|
|
LeakyResetEnv(kDyldInsertLibraries, new_env);
|
|
|
|
}
|
2016-04-27 12:56:16 +00:00
|
|
|
#endif // SANITIZER_GO
|
2015-12-03 10:39:43 +00:00
|
|
|
|
2016-01-18 07:55:12 +00:00
|
|
|
char **GetArgv() {
|
|
|
|
return *_NSGetArgv();
|
|
|
|
}
|
2017-07-06 20:38:33 +00:00
|
|
|
|
2020-12-14 10:48:48 -08:00
|
|
|
#if SANITIZER_IOS && !SANITIZER_IOSSIM
|
2017-07-06 20:30:09 +00:00
|
|
|
// The task_vm_info struct is normally provided by the macOS SDK, but we need
|
|
|
|
// fields only available in 10.12+. Declare the struct manually to be able to
|
|
|
|
// build against older SDKs.
|
|
|
|
struct __sanitizer_task_vm_info {
|
2017-07-13 20:02:45 +00:00
|
|
|
mach_vm_size_t virtual_size;
|
|
|
|
integer_t region_count;
|
|
|
|
integer_t page_size;
|
|
|
|
mach_vm_size_t resident_size;
|
|
|
|
mach_vm_size_t resident_size_peak;
|
|
|
|
mach_vm_size_t device;
|
|
|
|
mach_vm_size_t device_peak;
|
|
|
|
mach_vm_size_t internal;
|
|
|
|
mach_vm_size_t internal_peak;
|
|
|
|
mach_vm_size_t external;
|
|
|
|
mach_vm_size_t external_peak;
|
|
|
|
mach_vm_size_t reusable;
|
|
|
|
mach_vm_size_t reusable_peak;
|
|
|
|
mach_vm_size_t purgeable_volatile_pmap;
|
|
|
|
mach_vm_size_t purgeable_volatile_resident;
|
|
|
|
mach_vm_size_t purgeable_volatile_virtual;
|
|
|
|
mach_vm_size_t compressed;
|
|
|
|
mach_vm_size_t compressed_peak;
|
|
|
|
mach_vm_size_t compressed_lifetime;
|
|
|
|
mach_vm_size_t phys_footprint;
|
|
|
|
mach_vm_address_t min_address;
|
|
|
|
mach_vm_address_t max_address;
|
2017-07-06 20:30:09 +00:00
|
|
|
};
|
2017-07-13 20:02:45 +00:00
|
|
|
#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \
|
|
|
|
(sizeof(__sanitizer_task_vm_info) / sizeof(natural_t)))
|
2017-07-06 20:30:09 +00:00
|
|
|
|
2019-06-21 21:01:39 +00:00
|
|
|
static uptr GetTaskInfoMaxAddress() {
|
2018-08-17 17:53:14 +00:00
|
|
|
__sanitizer_task_vm_info vm_info = {} /* zero initialize */;
|
2017-07-13 20:02:45 +00:00
|
|
|
mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT;
|
2017-07-06 20:30:09 +00:00
|
|
|
int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count);
|
2019-06-21 21:01:39 +00:00
|
|
|
return err ? 0 : vm_info.max_address;
|
2017-07-06 20:30:09 +00:00
|
|
|
}
|
2016-01-18 07:55:12 +00:00
|
|
|
|
2017-11-07 23:51:22 +00:00
|
|
|
uptr GetMaxUserVirtualAddress() {
|
2017-07-06 20:30:09 +00:00
|
|
|
static uptr max_vm = GetTaskInfoMaxAddress();
|
2021-04-09 17:47:54 -07:00
|
|
|
if (max_vm != 0) {
|
2021-04-09 17:47:54 -07:00
|
|
|
const uptr ret_value = max_vm - 1;
|
|
|
|
CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);
|
|
|
|
return ret_value;
|
2021-04-09 17:47:54 -07:00
|
|
|
}
|
2019-06-21 21:01:39 +00:00
|
|
|
|
|
|
|
// xnu cannot provide vm address limit
|
|
|
|
# if SANITIZER_WORDSIZE == 32
|
2021-04-09 17:47:54 -07:00
|
|
|
constexpr uptr fallback_max_vm = 0xffe00000 - 1;
|
2017-07-06 17:13:40 +00:00
|
|
|
# else
|
2021-04-09 17:47:54 -07:00
|
|
|
constexpr uptr fallback_max_vm = 0x200000000 - 1;
|
2017-07-06 17:13:40 +00:00
|
|
|
# endif
|
2021-04-09 17:47:54 -07:00
|
|
|
static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
|
|
|
|
"Max virtual address must be less than mmap range size.");
|
|
|
|
return fallback_max_vm;
|
2019-06-21 21:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else // !SANITIZER_IOS
|
|
|
|
|
|
|
|
uptr GetMaxUserVirtualAddress() {
|
|
|
|
# if SANITIZER_WORDSIZE == 64
|
2021-04-09 17:47:54 -07:00
|
|
|
constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
|
2019-06-21 21:01:39 +00:00
|
|
|
# else // SANITIZER_WORDSIZE == 32
|
|
|
|
static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
|
2021-04-09 17:47:54 -07:00
|
|
|
constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;
|
2019-06-21 21:01:39 +00:00
|
|
|
# endif
|
2021-04-09 17:47:54 -07:00
|
|
|
static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
|
|
|
|
"Max virtual address must be less than mmap range size.");
|
|
|
|
return max_vm;
|
2017-07-06 17:13:40 +00:00
|
|
|
}
|
2019-06-21 21:01:39 +00:00
|
|
|
#endif
|
2017-07-06 17:13:40 +00:00
|
|
|
|
2017-11-20 17:41:57 +00:00
|
|
|
uptr GetMaxVirtualAddress() {
|
|
|
|
return GetMaxUserVirtualAddress();
|
|
|
|
}
|
|
|
|
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-06 11:05:12 -07:00
|
|
|
uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
|
|
|
|
uptr min_shadow_base_alignment, uptr &high_mem_end) {
|
|
|
|
const uptr granularity = GetMmapGranularity();
|
|
|
|
const uptr alignment =
|
|
|
|
Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
|
|
|
|
const uptr left_padding =
|
|
|
|
Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
|
|
|
|
|
|
|
|
uptr space_size = shadow_size_bytes + left_padding;
|
|
|
|
|
|
|
|
uptr largest_gap_found = 0;
|
|
|
|
uptr max_occupied_addr = 0;
|
2021-12-17 09:16:07 -05:00
|
|
|
VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-06 11:05:12 -07:00
|
|
|
uptr shadow_start =
|
|
|
|
FindAvailableMemoryRange(space_size, alignment, granularity,
|
|
|
|
&largest_gap_found, &max_occupied_addr);
|
|
|
|
// If the shadow doesn't fit, restrict the address space to make it fit.
|
|
|
|
if (shadow_start == 0) {
|
|
|
|
VReport(
|
|
|
|
2,
|
|
|
|
"Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n",
|
2021-12-17 09:16:07 -05:00
|
|
|
(void *)largest_gap_found, (void *)max_occupied_addr);
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-06 11:05:12 -07:00
|
|
|
uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment);
|
|
|
|
if (new_max_vm < max_occupied_addr) {
|
|
|
|
Report("Unable to find a memory range for dynamic shadow.\n");
|
|
|
|
Report(
|
|
|
|
"space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, "
|
|
|
|
"new_max_vm = %p\n",
|
2021-12-17 09:16:07 -05:00
|
|
|
(void *)space_size, (void *)largest_gap_found,
|
|
|
|
(void *)max_occupied_addr, (void *)new_max_vm);
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-06 11:05:12 -07:00
|
|
|
CHECK(0 && "cannot place shadow");
|
|
|
|
}
|
|
|
|
RestrictMemoryToMaxAddress(new_max_vm);
|
|
|
|
high_mem_end = new_max_vm - 1;
|
|
|
|
space_size = (high_mem_end >> shadow_scale) + left_padding;
|
2021-12-17 09:16:07 -05:00
|
|
|
VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-06 11:05:12 -07:00
|
|
|
shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity,
|
|
|
|
nullptr, nullptr);
|
|
|
|
if (shadow_start == 0) {
|
|
|
|
Report("Unable to find a memory range after restricting VM.\n");
|
|
|
|
CHECK(0 && "cannot place shadow after restricting vm");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CHECK_NE((uptr)0, shadow_start);
|
|
|
|
CHECK(IsAligned(shadow_start, alignment));
|
|
|
|
return shadow_start;
|
2021-03-23 11:21:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
|
|
|
|
uptr num_aliases, uptr ring_buffer_size) {
|
|
|
|
CHECK(false && "HWASan aliasing is unimplemented on Mac");
|
|
|
|
return 0;
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-06 11:05:12 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 18:33:21 +00:00
|
|
|
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
|
|
|
|
uptr *largest_gap_found,
|
|
|
|
uptr *max_occupied_addr) {
|
2016-10-05 20:33:59 +00:00
|
|
|
typedef vm_region_submap_short_info_data_64_t RegionInfo;
|
|
|
|
enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
|
|
|
|
// Start searching for available memory region past PAGEZERO, which is
|
|
|
|
// 4KB on 32-bit and 4GB on 64-bit.
|
|
|
|
mach_vm_address_t start_address =
|
|
|
|
(SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000;
|
|
|
|
|
2022-09-20 15:23:58 -07:00
|
|
|
const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;
|
2016-10-05 20:33:59 +00:00
|
|
|
mach_vm_address_t address = start_address;
|
|
|
|
mach_vm_address_t free_begin = start_address;
|
|
|
|
kern_return_t kr = KERN_SUCCESS;
|
2017-07-12 23:29:21 +00:00
|
|
|
if (largest_gap_found) *largest_gap_found = 0;
|
2018-02-26 18:33:21 +00:00
|
|
|
if (max_occupied_addr) *max_occupied_addr = 0;
|
2016-10-05 20:33:59 +00:00
|
|
|
while (kr == KERN_SUCCESS) {
|
|
|
|
mach_vm_size_t vmsize = 0;
|
|
|
|
natural_t depth = 0;
|
|
|
|
RegionInfo vminfo;
|
|
|
|
mach_msg_type_number_t count = kRegionInfoSize;
|
|
|
|
kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,
|
|
|
|
(vm_region_info_t)&vminfo, &count);
|
2017-11-29 19:44:52 +00:00
|
|
|
if (kr == KERN_INVALID_ADDRESS) {
|
|
|
|
// No more regions beyond "address", consider the gap at the end of VM.
|
2022-09-20 15:23:58 -07:00
|
|
|
address = max_vm_address;
|
2017-11-29 19:44:52 +00:00
|
|
|
vmsize = 0;
|
2018-02-26 18:33:21 +00:00
|
|
|
} else {
|
|
|
|
if (max_occupied_addr) *max_occupied_addr = address + vmsize;
|
2017-11-29 19:44:52 +00:00
|
|
|
}
|
2016-10-05 20:33:59 +00:00
|
|
|
if (free_begin != address) {
|
|
|
|
// We found a free region [free_begin..address-1].
|
2017-07-12 23:29:21 +00:00
|
|
|
uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);
|
2022-09-20 15:23:58 -07:00
|
|
|
uptr gap_end = RoundDownTo((uptr)Min(address, max_vm_address), alignment);
|
2017-07-12 23:29:21 +00:00
|
|
|
uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0;
|
2018-02-26 18:33:21 +00:00
|
|
|
if (size < gap_size) {
|
2017-07-12 23:29:21 +00:00
|
|
|
return gap_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (largest_gap_found && *largest_gap_found < gap_size) {
|
|
|
|
*largest_gap_found = gap_size;
|
2016-10-05 20:33:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Move to the next region.
|
|
|
|
address += vmsize;
|
|
|
|
free_begin = address;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We looked at all free regions and could not find one large enough.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-21 22:18:36 +00:00
|
|
|
// FIXME implement on this platform.
|
2021-10-29 10:31:37 +02:00
|
|
|
void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
|
2016-07-21 22:18:36 +00:00
|
|
|
|
2016-11-26 00:50:08 +00:00
|
|
|
void SignalContext::DumpAllRegisters(void *context) {
|
|
|
|
Report("Register values:\n");
|
|
|
|
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
# define DUMPREG64(r) \
|
|
|
|
Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r);
|
2020-04-29 12:55:21 -07:00
|
|
|
# define DUMPREGA64(r) \
|
2021-12-17 09:36:16 -05:00
|
|
|
Printf(" %s = 0x%016lx ", #r, AARCH64_GET_REG(r));
|
2016-11-26 00:50:08 +00:00
|
|
|
# define DUMPREG32(r) \
|
|
|
|
Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);
|
|
|
|
# define DUMPREG_(r) Printf(" "); DUMPREG(r);
|
|
|
|
# define DUMPREG__(r) Printf(" "); DUMPREG(r);
|
|
|
|
# define DUMPREG___(r) Printf(" "); DUMPREG(r);
|
|
|
|
|
|
|
|
# if defined(__x86_64__)
|
|
|
|
# define DUMPREG(r) DUMPREG64(r)
|
|
|
|
DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n");
|
|
|
|
DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n");
|
|
|
|
DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n");
|
|
|
|
DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n");
|
|
|
|
# elif defined(__i386__)
|
|
|
|
# define DUMPREG(r) DUMPREG32(r)
|
|
|
|
DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n");
|
|
|
|
DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n");
|
|
|
|
# elif defined(__aarch64__)
|
|
|
|
# define DUMPREG(r) DUMPREG64(r)
|
|
|
|
DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n");
|
|
|
|
DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n");
|
|
|
|
DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n");
|
|
|
|
DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n");
|
|
|
|
DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");
|
|
|
|
DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");
|
|
|
|
DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");
|
2020-04-29 12:55:21 -07:00
|
|
|
DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");
|
2016-11-26 00:50:08 +00:00
|
|
|
# elif defined(__arm__)
|
|
|
|
# define DUMPREG(r) DUMPREG32(r)
|
|
|
|
DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");
|
|
|
|
DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n");
|
|
|
|
DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n");
|
|
|
|
DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n");
|
|
|
|
# else
|
|
|
|
# error "Unknown architecture"
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# undef DUMPREG64
|
|
|
|
# undef DUMPREG32
|
|
|
|
# undef DUMPREG_
|
|
|
|
# undef DUMPREG__
|
|
|
|
# undef DUMPREG___
|
|
|
|
# undef DUMPREG
|
|
|
|
}
|
|
|
|
|
2017-01-06 20:57:47 +00:00
|
|
|
static inline bool CompareBaseAddress(const LoadedModule &a,
|
|
|
|
const LoadedModule &b) {
|
|
|
|
return a.base_address() < b.base_address();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FormatUUID(char *out, uptr size, const u8 *uuid) {
|
|
|
|
internal_snprintf(out, size,
|
|
|
|
"<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-"
|
|
|
|
"%02X%02X%02X%02X%02X%02X>",
|
|
|
|
uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
|
|
|
|
uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
|
|
|
|
uuid[12], uuid[13], uuid[14], uuid[15]);
|
|
|
|
}
|
|
|
|
|
2020-10-17 10:46:19 -07:00
|
|
|
void DumpProcessMap() {
|
2017-01-06 20:57:47 +00:00
|
|
|
Printf("Process module map:\n");
|
|
|
|
MemoryMappingLayout memory_mapping(false);
|
2018-05-07 05:56:24 +00:00
|
|
|
InternalMmapVector<LoadedModule> modules;
|
|
|
|
modules.reserve(128);
|
2017-01-06 20:57:47 +00:00
|
|
|
memory_mapping.DumpListOfModules(&modules);
|
2018-05-09 20:42:11 +00:00
|
|
|
Sort(modules.data(), modules.size(), CompareBaseAddress);
|
2017-01-06 20:57:47 +00:00
|
|
|
for (uptr i = 0; i < modules.size(); ++i) {
|
|
|
|
char uuid_str[128];
|
|
|
|
FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());
|
|
|
|
Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(),
|
2022-04-01 16:35:33 +02:00
|
|
|
modules[i].max_address(), modules[i].full_name(),
|
2017-01-06 20:57:47 +00:00
|
|
|
ModuleArchToString(modules[i].arch()), uuid_str);
|
|
|
|
}
|
|
|
|
Printf("End of module map.\n");
|
|
|
|
}
|
|
|
|
|
2017-03-09 10:47:38 +00:00
|
|
|
void CheckNoDeepBind(const char *filename, int flag) {
|
|
|
|
// Do nothing.
|
|
|
|
}
|
|
|
|
|
2017-08-14 14:53:47 +00:00
|
|
|
bool GetRandom(void *buffer, uptr length, bool blocking) {
|
2018-08-24 16:53:06 +00:00
|
|
|
if (!buffer || !length || length > 256)
|
|
|
|
return false;
|
|
|
|
// arc4random never fails.
|
2019-08-19 18:12:15 +00:00
|
|
|
REAL(arc4random_buf)(buffer, length);
|
2018-08-24 16:53:06 +00:00
|
|
|
return true;
|
[sanitizer] Add a function to gather random bytes
Summary:
AFAICT compiler-rt doesn't have a function that would return 'good' random
bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses
returned by `mmap` to seed its PRNG, which is not ideal, and
`SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit
counterpart address space, so right now it has nothing. This function aims at
solving this, allowing to implement good 32-bit chunk randomization. Scudo also
has a function that does this for Cookie purposes, which would go away in a
later CL once this lands.
This function will try the `getrandom` syscall if available, and fallback to
`/dev/urandom` if not.
Unfortunately, I do not have a way to implement and test a Mac and Windows
version, so those are unimplemented as of now. Note that `kRandomShuffleChunks`
is only used on Linux for now.
Reviewers: alekseyshl
Reviewed By: alekseyshl
Subscribers: zturner, rnk, llvm-commits, kubamracek
Differential Revision: https://reviews.llvm.org/D34412
llvm-svn: 305922
2017-06-21 15:56:03 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 21:14:00 +00:00
|
|
|
u32 GetNumberOfCPUs() {
|
2018-08-24 16:53:06 +00:00
|
|
|
return (u32)sysconf(_SC_NPROCESSORS_ONLN);
|
2017-11-21 21:14:00 +00:00
|
|
|
}
|
|
|
|
|
2020-11-04 18:52:15 -08:00
|
|
|
void InitializePlatformCommonFlags(CommonFlags *cf) {}
|
|
|
|
|
2022-07-22 11:33:35 -07:00
|
|
|
// Pthread introspection hook
|
|
|
|
//
|
|
|
|
// * GCD worker threads are created without a call to pthread_create(), but we
|
|
|
|
// still need to register these threads (with ThreadCreate/Start()).
|
|
|
|
// * We use the "pthread introspection hook" below to observe the creation of
|
|
|
|
// such threads.
|
|
|
|
// * GCD worker threads don't have parent threads and the CREATE event is
|
|
|
|
// delivered in the context of the thread itself. CREATE events for regular
|
|
|
|
// threads, are delivered on the parent. We use this to tell apart which
|
|
|
|
// threads are GCD workers with `thread == pthread_self()`.
|
|
|
|
//
|
|
|
|
static pthread_introspection_hook_t prev_pthread_introspection_hook;
|
|
|
|
static ThreadEventCallbacks thread_event_callbacks;
|
|
|
|
|
|
|
|
static void sanitizer_pthread_introspection_hook(unsigned int event,
|
|
|
|
pthread_t thread, void *addr,
|
|
|
|
size_t size) {
|
|
|
|
// create -> start -> terminate -> destroy
|
|
|
|
// * create/destroy are usually (not guaranteed) delivered on the parent and
|
|
|
|
// track resource allocation/reclamation
|
|
|
|
// * start/terminate are guaranteed to be delivered in the context of the
|
|
|
|
// thread and give hooks into "just after (before) thread starts (stops)
|
|
|
|
// executing"
|
|
|
|
DCHECK(event >= PTHREAD_INTROSPECTION_THREAD_CREATE &&
|
|
|
|
event <= PTHREAD_INTROSPECTION_THREAD_DESTROY);
|
|
|
|
|
|
|
|
if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
|
|
|
|
bool gcd_worker = (thread == pthread_self());
|
|
|
|
if (thread_event_callbacks.create)
|
|
|
|
thread_event_callbacks.create((uptr)thread, gcd_worker);
|
|
|
|
} else if (event == PTHREAD_INTROSPECTION_THREAD_START) {
|
|
|
|
CHECK_EQ(thread, pthread_self());
|
|
|
|
if (thread_event_callbacks.start)
|
|
|
|
thread_event_callbacks.start((uptr)thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prev_pthread_introspection_hook)
|
|
|
|
prev_pthread_introspection_hook(event, thread, addr, size);
|
|
|
|
|
|
|
|
if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
|
|
|
|
CHECK_EQ(thread, pthread_self());
|
|
|
|
if (thread_event_callbacks.terminate)
|
|
|
|
thread_event_callbacks.terminate((uptr)thread);
|
|
|
|
} else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {
|
|
|
|
if (thread_event_callbacks.destroy)
|
|
|
|
thread_event_callbacks.destroy((uptr)thread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InstallPthreadIntrospectionHook(const ThreadEventCallbacks &callbacks) {
|
|
|
|
thread_event_callbacks = callbacks;
|
|
|
|
prev_pthread_introspection_hook =
|
|
|
|
pthread_introspection_hook_install(&sanitizer_pthread_introspection_hook);
|
|
|
|
}
|
|
|
|
|
2012-06-04 14:27:50 +00:00
|
|
|
} // namespace __sanitizer
|
|
|
|
|
2022-05-23 14:35:42 -07:00
|
|
|
#endif // SANITIZER_APPLE
|