brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.9 KiB · 598a55d Raw
208 lines · cpp
1//===-- asan_posix.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of AddressSanitizer, an address sanity checker.10//11// Posix-specific details.12//===----------------------------------------------------------------------===//13 14#include "sanitizer_common/sanitizer_platform.h"15#if SANITIZER_POSIX16 17#  include <pthread.h>18#  include <signal.h>19#  include <stdlib.h>20#  include <sys/resource.h>21#  include <sys/time.h>22#  include <unistd.h>23 24#  include "asan_interceptors.h"25#  include "asan_internal.h"26#  include "asan_mapping.h"27#  include "asan_poisoning.h"28#  include "asan_report.h"29#  include "asan_stack.h"30#  include "lsan/lsan_common.h"31#  include "sanitizer_common/sanitizer_libc.h"32#  include "sanitizer_common/sanitizer_posix.h"33#  include "sanitizer_common/sanitizer_procmaps.h"34 35namespace __asan {36 37void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {38  StartReportDeadlySignal();39  SignalContext sig(siginfo, context);40  ReportDeadlySignal(sig);41}42 43bool PlatformUnpoisonStacks() {44  stack_t signal_stack;45  CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));46  uptr sigalt_bottom = (uptr)signal_stack.ss_sp;47  uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);48  // If we're executing on the signal alternate stack AND the Linux flag49  // SS_AUTODISARM was used, then we cannot get the signal alternate stack50  // bounds from sigaltstack -- sigaltstack's output looks just as if no51  // alternate stack has ever been set up.52  // We're always unpoisoning the signal alternate stack to support jumping53  // between the default stack and signal alternate stack.54  if (signal_stack.ss_flags != SS_DISABLE)55    UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");56 57  if (signal_stack.ss_flags != SS_ONSTACK)58    return false;59 60  // Since we're on the signal alternate stack, we cannot find the DEFAULT61  // stack bottom using a local variable.62  uptr stack_begin, stack_end, tls_begin, tls_end;63  GetThreadStackAndTls(/*main=*/false, &stack_begin, &stack_end, &tls_begin,64                       &tls_end);65  UnpoisonStack(stack_begin, stack_end, "default");66  return true;67}68 69// ---------------------- TSD ---------------- {{{170 71#if SANITIZER_NETBSD && !ASAN_DYNAMIC72// Thread Static Data cannot be used in early static ASan init on NetBSD.73// Reuse the Asan TSD API for compatibility with existing code74// with an alternative implementation.75 76static void (*tsd_destructor)(void *tsd) = nullptr;77 78struct tsd_key {79  tsd_key() : key(nullptr) {}80  ~tsd_key() {81    CHECK(tsd_destructor);82    if (key)83      (*tsd_destructor)(key);84  }85  void *key;86};87 88static thread_local struct tsd_key key;89 90void AsanTSDInit(void (*destructor)(void *tsd)) {91  CHECK(!tsd_destructor);92  tsd_destructor = destructor;93}94 95void *AsanTSDGet() {96  CHECK(tsd_destructor);97  return key.key;98}99 100void AsanTSDSet(void *tsd) {101  CHECK(tsd_destructor);102  CHECK(tsd);103  CHECK(!key.key);104  key.key = tsd;105}106 107void PlatformTSDDtor(void *tsd) {108  CHECK(tsd_destructor);109  CHECK_EQ(key.key, tsd);110  key.key = nullptr;111  // Make sure that signal handler can not see a stale current thread pointer.112  atomic_signal_fence(memory_order_seq_cst);113  AsanThread::TSDDtor(tsd);114}115#else116static pthread_key_t tsd_key;117static bool tsd_key_inited = false;118void AsanTSDInit(void (*destructor)(void *tsd)) {119  CHECK(!tsd_key_inited);120  tsd_key_inited = true;121  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));122}123 124void *AsanTSDGet() {125  CHECK(tsd_key_inited);126  return pthread_getspecific(tsd_key);127}128 129void AsanTSDSet(void *tsd) {130  CHECK(tsd_key_inited);131  pthread_setspecific(tsd_key, tsd);132}133 134void PlatformTSDDtor(void *tsd) {135  AsanThreadContext *context = (AsanThreadContext *)tsd;136  if (context->destructor_iterations > 1) {137    context->destructor_iterations--;138    CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));139    return;140  }141#    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \142        SANITIZER_SOLARIS143  // After this point it's unsafe to execute signal handlers which may be144  // instrumented. It's probably not just a Linux issue.145  BlockSignals();146#    endif147  AsanThread::TSDDtor(tsd);148}149#  endif150 151static void BeforeFork() {152  VReport(2, "BeforeFork tid: %llu\n", GetTid());153  if (CAN_SANITIZE_LEAKS) {154    __lsan::LockGlobal();155  }156  // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the157  // stuff we need.158  __lsan::LockThreads();159  __lsan::LockAllocator();160 161  AcquirePoisonRecords();162 163  StackDepotLockBeforeFork();164}165 166static void AfterFork(bool fork_child) {167  StackDepotUnlockAfterFork(fork_child);168 169  ReleasePoisonRecords();170 171  // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock172  // the stuff we need.173  __lsan::UnlockAllocator();174  __lsan::UnlockThreads();175  if (CAN_SANITIZE_LEAKS) {176    __lsan::UnlockGlobal();177  }178  VReport(2, "AfterFork tid: %llu\n", GetTid());179}180 181void InstallAtForkHandler() {182#  if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \183      (SANITIZER_LINUX && SANITIZER_SPARC) || SANITIZER_HAIKU || SANITIZER_AIX184  // While other Linux targets use clone in internal_fork which doesn't185  // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a186  // hang.187  return;  // FIXME: Implement FutexWait.188#  endif189  pthread_atfork(190      &BeforeFork, []() { AfterFork(/* fork_child= */ false); },191      []() { AfterFork(/* fork_child= */ true); });192}193 194void InstallAtExitCheckLeaks() {195  if (CAN_SANITIZE_LEAKS) {196    if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {197      if (flags()->halt_on_error)198        Atexit(__lsan::DoLeakCheck);199      else200        Atexit(__lsan::DoRecoverableLeakCheckVoid);201    }202  }203}204 205}  // namespace __asan206 207#endif  // SANITIZER_POSIX208