mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-06 09:28:50 +00:00

This is a re-land of https://reviews.llvm.org/D86171 with fix. Fuchsia's system libraries are instrumented and use the lsan allocator for internal purposes. So leak checking needs to run after all atexit hooks and after the system libraries' internal exit-time hooks. The <zircon/sanitizer.h> hook API calls the __sanitizer_process_exit_hook function at exactly the right time. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D88248
159 lines
4.5 KiB
C++
159 lines
4.5 KiB
C++
//===-- asan_posix.cpp ----------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of AddressSanitizer, an address sanity checker.
|
|
//
|
|
// Posix-specific details.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "sanitizer_common/sanitizer_platform.h"
|
|
#if SANITIZER_POSIX
|
|
|
|
# include <pthread.h>
|
|
# include <signal.h>
|
|
# include <stdlib.h>
|
|
# include <sys/resource.h>
|
|
# include <sys/time.h>
|
|
# include <unistd.h>
|
|
|
|
# include "asan_interceptors.h"
|
|
# include "asan_internal.h"
|
|
# include "asan_mapping.h"
|
|
# include "asan_poisoning.h"
|
|
# include "asan_report.h"
|
|
# include "asan_stack.h"
|
|
# include "lsan/lsan_common.h"
|
|
# include "sanitizer_common/sanitizer_libc.h"
|
|
# include "sanitizer_common/sanitizer_posix.h"
|
|
# include "sanitizer_common/sanitizer_procmaps.h"
|
|
|
|
namespace __asan {
|
|
|
|
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
|
|
StartReportDeadlySignal();
|
|
SignalContext sig(siginfo, context);
|
|
ReportDeadlySignal(sig);
|
|
}
|
|
|
|
bool PlatformUnpoisonStacks() {
|
|
stack_t signal_stack;
|
|
CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
|
|
uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
|
|
uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);
|
|
// If we're executing on the signal alternate stack AND the Linux flag
|
|
// SS_AUTODISARM was used, then we cannot get the signal alternate stack
|
|
// bounds from sigaltstack -- sigaltstack's output looks just as if no
|
|
// alternate stack has ever been set up.
|
|
// We're always unpoisoning the signal alternate stack to support jumping
|
|
// between the default stack and signal alternate stack.
|
|
if (signal_stack.ss_flags != SS_DISABLE)
|
|
UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");
|
|
|
|
if (signal_stack.ss_flags != SS_ONSTACK)
|
|
return false;
|
|
|
|
// Since we're on the signal alternate stack, we cannot find the DEFAULT
|
|
// stack bottom using a local variable.
|
|
uptr default_bottom, tls_addr, tls_size, stack_size;
|
|
GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
|
|
&tls_size);
|
|
UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
|
|
return true;
|
|
}
|
|
|
|
// ---------------------- TSD ---------------- {{{1
|
|
|
|
#if SANITIZER_NETBSD && !ASAN_DYNAMIC
|
|
// Thread Static Data cannot be used in early static ASan init on NetBSD.
|
|
// Reuse the Asan TSD API for compatibility with existing code
|
|
// with an alternative implementation.
|
|
|
|
static void (*tsd_destructor)(void *tsd) = nullptr;
|
|
|
|
struct tsd_key {
|
|
tsd_key() : key(nullptr) {}
|
|
~tsd_key() {
|
|
CHECK(tsd_destructor);
|
|
if (key)
|
|
(*tsd_destructor)(key);
|
|
}
|
|
void *key;
|
|
};
|
|
|
|
static thread_local struct tsd_key key;
|
|
|
|
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
|
CHECK(!tsd_destructor);
|
|
tsd_destructor = destructor;
|
|
}
|
|
|
|
void *AsanTSDGet() {
|
|
CHECK(tsd_destructor);
|
|
return key.key;
|
|
}
|
|
|
|
void AsanTSDSet(void *tsd) {
|
|
CHECK(tsd_destructor);
|
|
CHECK(tsd);
|
|
CHECK(!key.key);
|
|
key.key = tsd;
|
|
}
|
|
|
|
void PlatformTSDDtor(void *tsd) {
|
|
CHECK(tsd_destructor);
|
|
CHECK_EQ(key.key, tsd);
|
|
key.key = nullptr;
|
|
// Make sure that signal handler can not see a stale current thread pointer.
|
|
atomic_signal_fence(memory_order_seq_cst);
|
|
AsanThread::TSDDtor(tsd);
|
|
}
|
|
#else
|
|
static pthread_key_t tsd_key;
|
|
static bool tsd_key_inited = false;
|
|
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
|
CHECK(!tsd_key_inited);
|
|
tsd_key_inited = true;
|
|
CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
|
|
}
|
|
|
|
void *AsanTSDGet() {
|
|
CHECK(tsd_key_inited);
|
|
return pthread_getspecific(tsd_key);
|
|
}
|
|
|
|
void AsanTSDSet(void *tsd) {
|
|
CHECK(tsd_key_inited);
|
|
pthread_setspecific(tsd_key, tsd);
|
|
}
|
|
|
|
void PlatformTSDDtor(void *tsd) {
|
|
AsanThreadContext *context = (AsanThreadContext *)tsd;
|
|
if (context->destructor_iterations > 1) {
|
|
context->destructor_iterations--;
|
|
CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
|
|
return;
|
|
}
|
|
AsanThread::TSDDtor(tsd);
|
|
}
|
|
#endif
|
|
|
|
void InstallAtExitCheckLeaks() {
|
|
if (CAN_SANITIZE_LEAKS) {
|
|
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
|
|
if (flags()->halt_on_error)
|
|
Atexit(__lsan::DoLeakCheck);
|
|
else
|
|
Atexit(__lsan::DoRecoverableLeakCheckVoid);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace __asan
|
|
|
|
#endif // SANITIZER_POSIX
|