| //===-- 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 |