206 lines
5.6 KiB
C++
206 lines
5.6 KiB
C++
//===-- sanitizer_posix_libcdep.cc ----------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is shared between AddressSanitizer and ThreadSanitizer
|
|
// run-time libraries and implements libc-dependent POSIX-specific functions
|
|
// from sanitizer_libc.h.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "sanitizer_platform.h"
|
|
|
|
#if SANITIZER_POSIX
|
|
#include "sanitizer_common.h"
|
|
#include "sanitizer_flags.h"
|
|
#include "sanitizer_platform_limits_posix.h"
|
|
#include "sanitizer_stacktrace.h"
|
|
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
namespace __sanitizer {
|
|
|
|
u32 GetUid() {
|
|
return getuid();
|
|
}
|
|
|
|
uptr GetThreadSelf() {
|
|
return (uptr)pthread_self();
|
|
}
|
|
|
|
void FlushUnneededShadowMemory(uptr addr, uptr size) {
|
|
madvise((void*)addr, size, MADV_DONTNEED);
|
|
}
|
|
|
|
void NoHugePagesInRegion(uptr addr, uptr size) {
|
|
#ifdef MADV_NOHUGEPAGE // May not be defined on old systems.
|
|
madvise((void *)addr, size, MADV_NOHUGEPAGE);
|
|
#endif // MADV_NOHUGEPAGE
|
|
}
|
|
|
|
void DontDumpShadowMemory(uptr addr, uptr length) {
|
|
#ifdef MADV_DONTDUMP
|
|
madvise((void *)addr, length, MADV_DONTDUMP);
|
|
#endif
|
|
}
|
|
|
|
static rlim_t getlim(int res) {
|
|
rlimit rlim;
|
|
CHECK_EQ(0, getrlimit(res, &rlim));
|
|
return rlim.rlim_cur;
|
|
}
|
|
|
|
static void setlim(int res, rlim_t lim) {
|
|
// The following magic is to prevent clang from replacing it with memset.
|
|
volatile struct rlimit rlim;
|
|
rlim.rlim_cur = lim;
|
|
rlim.rlim_max = lim;
|
|
if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
|
|
Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
|
|
Die();
|
|
}
|
|
}
|
|
|
|
void DisableCoreDumperIfNecessary() {
|
|
if (common_flags()->disable_coredump) {
|
|
setlim(RLIMIT_CORE, 0);
|
|
}
|
|
}
|
|
|
|
bool StackSizeIsUnlimited() {
|
|
rlim_t stack_size = getlim(RLIMIT_STACK);
|
|
return (stack_size == RLIM_INFINITY);
|
|
}
|
|
|
|
void SetStackSizeLimitInBytes(uptr limit) {
|
|
setlim(RLIMIT_STACK, (rlim_t)limit);
|
|
CHECK(!StackSizeIsUnlimited());
|
|
}
|
|
|
|
bool AddressSpaceIsUnlimited() {
|
|
rlim_t as_size = getlim(RLIMIT_AS);
|
|
return (as_size == RLIM_INFINITY);
|
|
}
|
|
|
|
void SetAddressSpaceUnlimited() {
|
|
setlim(RLIMIT_AS, RLIM_INFINITY);
|
|
CHECK(AddressSpaceIsUnlimited());
|
|
}
|
|
|
|
void SleepForSeconds(int seconds) {
|
|
sleep(seconds);
|
|
}
|
|
|
|
void SleepForMillis(int millis) {
|
|
usleep(millis * 1000);
|
|
}
|
|
|
|
void Abort() {
|
|
abort();
|
|
}
|
|
|
|
int Atexit(void (*function)(void)) {
|
|
#ifndef SANITIZER_GO
|
|
return atexit(function);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int internal_isatty(fd_t fd) {
|
|
return isatty(fd);
|
|
}
|
|
|
|
#ifndef SANITIZER_GO
|
|
// TODO(glider): different tools may require different altstack size.
|
|
static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
|
|
|
|
void SetAlternateSignalStack() {
|
|
stack_t altstack, oldstack;
|
|
CHECK_EQ(0, sigaltstack(0, &oldstack));
|
|
// If the alternate stack is already in place, do nothing.
|
|
// Android always sets an alternate stack, but it's too small for us.
|
|
if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
|
|
// TODO(glider): the mapped stack should have the MAP_STACK flag in the
|
|
// future. It is not required by man 2 sigaltstack now (they're using
|
|
// malloc()).
|
|
void* base = MmapOrDie(kAltStackSize, __func__);
|
|
altstack.ss_sp = (char*) base;
|
|
altstack.ss_flags = 0;
|
|
altstack.ss_size = kAltStackSize;
|
|
CHECK_EQ(0, sigaltstack(&altstack, 0));
|
|
}
|
|
|
|
void UnsetAlternateSignalStack() {
|
|
stack_t altstack, oldstack;
|
|
altstack.ss_sp = 0;
|
|
altstack.ss_flags = SS_DISABLE;
|
|
altstack.ss_size = kAltStackSize; // Some sane value required on Darwin.
|
|
CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
|
|
UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
|
|
}
|
|
|
|
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
|
|
static void MaybeInstallSigaction(int signum,
|
|
SignalHandlerType handler) {
|
|
if (!IsDeadlySignal(signum))
|
|
return;
|
|
struct sigaction sigact;
|
|
internal_memset(&sigact, 0, sizeof(sigact));
|
|
sigact.sa_sigaction = (sa_sigaction_t)handler;
|
|
// Do not block the signal from being received in that signal's handler.
|
|
// Clients are responsible for handling this correctly.
|
|
sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
|
|
if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
|
|
CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
|
|
VReport(1, "Installed the sigaction for signal %d\n", signum);
|
|
}
|
|
|
|
void InstallDeadlySignalHandlers(SignalHandlerType handler) {
|
|
// Set the alternate signal stack for the main thread.
|
|
// This will cause SetAlternateSignalStack to be called twice, but the stack
|
|
// will be actually set only once.
|
|
if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
|
|
MaybeInstallSigaction(SIGSEGV, handler);
|
|
MaybeInstallSigaction(SIGBUS, handler);
|
|
}
|
|
#endif // SANITIZER_GO
|
|
|
|
bool IsAccessibleMemoryRange(uptr beg, uptr size) {
|
|
uptr page_size = GetPageSizeCached();
|
|
// Checking too large memory ranges is slow.
|
|
CHECK_LT(size, page_size * 10);
|
|
int sock_pair[2];
|
|
if (pipe(sock_pair))
|
|
return false;
|
|
uptr bytes_written =
|
|
internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
|
|
int write_errno;
|
|
bool result;
|
|
if (internal_iserror(bytes_written, &write_errno)) {
|
|
CHECK_EQ(EFAULT, write_errno);
|
|
result = false;
|
|
} else {
|
|
result = (bytes_written == size);
|
|
}
|
|
internal_close(sock_pair[0]);
|
|
internal_close(sock_pair[1]);
|
|
return result;
|
|
}
|
|
|
|
} // namespace __sanitizer
|
|
|
|
#endif // SANITIZER_POSIX
|