asan_posix.cc revision cb8c4dce691097718d5af41b36899b72ef4b1d84
1//===-- asan_linux.cc -----------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of AddressSanitizer, an address sanity checker. 11// 12// Posix-specific details. 13//===----------------------------------------------------------------------===// 14#if defined(__linux__) || defined(__APPLE__) 15 16#include "asan_internal.h" 17#include "asan_interceptors.h" 18#include "asan_mapping.h" 19#include "asan_stack.h" 20#include "asan_thread_registry.h" 21#include "sanitizer_common/sanitizer_libc.h" 22#include "sanitizer_common/sanitizer_procmaps.h" 23 24#include <pthread.h> 25#include <signal.h> 26#include <stdlib.h> 27#include <sys/time.h> 28#include <sys/resource.h> 29#include <unistd.h> 30 31static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. 32 33namespace __asan { 34 35static void MaybeInstallSigaction(int signum, 36 void (*handler)(int, siginfo_t *, void *)) { 37 if (!AsanInterceptsSignal(signum)) 38 return; 39 struct sigaction sigact; 40 REAL(memset)(&sigact, 0, sizeof(sigact)); 41 sigact.sa_sigaction = handler; 42 sigact.sa_flags = SA_SIGINFO; 43 if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; 44 CHECK(0 == REAL(sigaction)(signum, &sigact, 0)); 45 if (flags()->verbosity >= 1) { 46 Report("Installed the sigaction for signal %d\n", signum); 47 } 48} 49 50static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { 51 uptr addr = (uptr)siginfo->si_addr; 52 // Write the first message using the bullet-proof write. 53 if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); 54 uptr pc, sp, bp; 55 GetPcSpBp(context, &pc, &sp, &bp); 56 AsanReport("ERROR: AddressSanitizer crashed on unknown address %p" 57 " (pc %p sp %p bp %p T%d)\n", 58 (void*)addr, (void*)pc, (void*)sp, (void*)bp, 59 asanThreadRegistry().GetCurrentTidOrInvalid()); 60 AsanPrintf("AddressSanitizer can not provide additional info. ABORTING\n"); 61 GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); 62 stack.PrintStack(); 63 ShowStatsAndAbort(); 64} 65 66void SetAlternateSignalStack() { 67 stack_t altstack, oldstack; 68 CHECK(0 == sigaltstack(0, &oldstack)); 69 // If the alternate stack is already in place, do nothing. 70 if ((oldstack.ss_flags & SS_DISABLE) == 0) return; 71 // TODO(glider): the mapped stack should have the MAP_STACK flag in the 72 // future. It is not required by man 2 sigaltstack now (they're using 73 // malloc()). 74 void* base = MmapOrDie(kAltStackSize, __FUNCTION__); 75 altstack.ss_sp = base; 76 altstack.ss_flags = 0; 77 altstack.ss_size = kAltStackSize; 78 CHECK(0 == sigaltstack(&altstack, 0)); 79 if (flags()->verbosity > 0) { 80 Report("Alternative stack for T%d set: [%p,%p)\n", 81 asanThreadRegistry().GetCurrentTidOrInvalid(), 82 altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); 83 } 84} 85 86void UnsetAlternateSignalStack() { 87 stack_t altstack, oldstack; 88 altstack.ss_sp = 0; 89 altstack.ss_flags = SS_DISABLE; 90 altstack.ss_size = 0; 91 CHECK(0 == sigaltstack(&altstack, &oldstack)); 92 UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); 93} 94 95void InstallSignalHandlers() { 96 // Set the alternate signal stack for the main thread. 97 // This will cause SetAlternateSignalStack to be called twice, but the stack 98 // will be actually set only once. 99 if (flags()->use_sigaltstack) SetAlternateSignalStack(); 100 MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); 101 MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); 102} 103 104// ---------------------- TSD ---------------- {{{1 105 106static pthread_key_t tsd_key; 107static bool tsd_key_inited = false; 108void AsanTSDInit(void (*destructor)(void *tsd)) { 109 CHECK(!tsd_key_inited); 110 tsd_key_inited = true; 111 CHECK(0 == pthread_key_create(&tsd_key, destructor)); 112} 113 114void *AsanTSDGet() { 115 CHECK(tsd_key_inited); 116 return pthread_getspecific(tsd_key); 117} 118 119void AsanTSDSet(void *tsd) { 120 CHECK(tsd_key_inited); 121 pthread_setspecific(tsd_key, tsd); 122} 123 124} // namespace __asan 125 126#endif // __linux__ || __APPLE_ 127