Path: blob/main/contrib/llvm-project/compiler-rt/lib/asan/asan_posix.cpp
35233 views
//===-- asan_posix.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of AddressSanitizer, an address sanity checker.9//10// Posix-specific details.11//===----------------------------------------------------------------------===//1213#include "sanitizer_common/sanitizer_platform.h"14#if SANITIZER_POSIX1516# include <pthread.h>17# include <signal.h>18# include <stdlib.h>19# include <sys/resource.h>20# include <sys/time.h>21# include <unistd.h>2223# include "asan_interceptors.h"24# include "asan_internal.h"25# include "asan_mapping.h"26# include "asan_poisoning.h"27# include "asan_report.h"28# include "asan_stack.h"29# include "lsan/lsan_common.h"30# include "sanitizer_common/sanitizer_libc.h"31# include "sanitizer_common/sanitizer_posix.h"32# include "sanitizer_common/sanitizer_procmaps.h"3334namespace __asan {3536void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {37StartReportDeadlySignal();38SignalContext sig(siginfo, context);39ReportDeadlySignal(sig);40}4142bool PlatformUnpoisonStacks() {43stack_t signal_stack;44CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));45uptr sigalt_bottom = (uptr)signal_stack.ss_sp;46uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);47// If we're executing on the signal alternate stack AND the Linux flag48// SS_AUTODISARM was used, then we cannot get the signal alternate stack49// bounds from sigaltstack -- sigaltstack's output looks just as if no50// alternate stack has ever been set up.51// We're always unpoisoning the signal alternate stack to support jumping52// between the default stack and signal alternate stack.53if (signal_stack.ss_flags != SS_DISABLE)54UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");5556if (signal_stack.ss_flags != SS_ONSTACK)57return false;5859// Since we're on the signal alternate stack, we cannot find the DEFAULT60// stack bottom using a local variable.61uptr default_bottom, tls_addr, tls_size, stack_size;62GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,63&tls_size);64UnpoisonStack(default_bottom, default_bottom + stack_size, "default");65return true;66}6768// ---------------------- TSD ---------------- {{{16970#if SANITIZER_NETBSD && !ASAN_DYNAMIC71// Thread Static Data cannot be used in early static ASan init on NetBSD.72// Reuse the Asan TSD API for compatibility with existing code73// with an alternative implementation.7475static void (*tsd_destructor)(void *tsd) = nullptr;7677struct tsd_key {78tsd_key() : key(nullptr) {}79~tsd_key() {80CHECK(tsd_destructor);81if (key)82(*tsd_destructor)(key);83}84void *key;85};8687static thread_local struct tsd_key key;8889void AsanTSDInit(void (*destructor)(void *tsd)) {90CHECK(!tsd_destructor);91tsd_destructor = destructor;92}9394void *AsanTSDGet() {95CHECK(tsd_destructor);96return key.key;97}9899void AsanTSDSet(void *tsd) {100CHECK(tsd_destructor);101CHECK(tsd);102CHECK(!key.key);103key.key = tsd;104}105106void PlatformTSDDtor(void *tsd) {107CHECK(tsd_destructor);108CHECK_EQ(key.key, tsd);109key.key = nullptr;110// Make sure that signal handler can not see a stale current thread pointer.111atomic_signal_fence(memory_order_seq_cst);112AsanThread::TSDDtor(tsd);113}114#else115static pthread_key_t tsd_key;116static bool tsd_key_inited = false;117void AsanTSDInit(void (*destructor)(void *tsd)) {118CHECK(!tsd_key_inited);119tsd_key_inited = true;120CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));121}122123void *AsanTSDGet() {124CHECK(tsd_key_inited);125return pthread_getspecific(tsd_key);126}127128void AsanTSDSet(void *tsd) {129CHECK(tsd_key_inited);130pthread_setspecific(tsd_key, tsd);131}132133void PlatformTSDDtor(void *tsd) {134AsanThreadContext *context = (AsanThreadContext *)tsd;135if (context->destructor_iterations > 1) {136context->destructor_iterations--;137CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));138return;139}140# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \141SANITIZER_SOLARIS142// After this point it's unsafe to execute signal handlers which may be143// instrumented. It's probably not just a Linux issue.144BlockSignals();145# endif146AsanThread::TSDDtor(tsd);147}148# endif149150static void BeforeFork() {151if (CAN_SANITIZE_LEAKS) {152__lsan::LockGlobal();153}154// `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the155// stuff we need.156__lsan::LockThreads();157__lsan::LockAllocator();158StackDepotLockBeforeFork();159}160161static void AfterFork(bool fork_child) {162StackDepotUnlockAfterFork(fork_child);163// `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock164// the stuff we need.165__lsan::UnlockAllocator();166__lsan::UnlockThreads();167if (CAN_SANITIZE_LEAKS) {168__lsan::UnlockGlobal();169}170}171172void InstallAtForkHandler() {173# if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE174return; // FIXME: Implement FutexWait.175# endif176pthread_atfork(177&BeforeFork, []() { AfterFork(/* fork_child= */ false); },178[]() { AfterFork(/* fork_child= */ true); });179}180181void InstallAtExitCheckLeaks() {182if (CAN_SANITIZE_LEAKS) {183if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {184if (flags()->halt_on_error)185Atexit(__lsan::DoLeakCheck);186else187Atexit(__lsan::DoRecoverableLeakCheckVoid);188}189}190}191192} // namespace __asan193194#endif // SANITIZER_POSIX195196197