asan_posix.cc revision 4c49666e611f06241bb8462cea7674d877241492
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 inline bool IntervalsAreSeparate(uptr start1, uptr end1, 36 uptr start2, uptr end2) { 37 CHECK(start1 <= end1); 38 CHECK(start2 <= end2); 39 return (end1 < start2) || (end2 < start1); 40} 41 42// FIXME: this is thread-unsafe, but should not cause problems most of the time. 43// When the shadow is mapped only a single thread usually exists (plus maybe 44// several worker threads on Mac, which aren't expected to map big chunks of 45// memory). 46bool AsanShadowRangeIsAvailable() { 47 ProcessMaps procmaps; 48 uptr start, end; 49 uptr shadow_start = kLowShadowBeg; 50 if (kLowShadowBeg > 0) shadow_start -= kMmapGranularity; 51 uptr shadow_end = kHighShadowEnd; 52 while (procmaps.Next(&start, &end, 53 /*offset*/0, /*filename*/0, /*filename_size*/0)) { 54 if (!IntervalsAreSeparate(start, end, shadow_start, shadow_end)) 55 return false; 56 } 57 return true; 58} 59 60static void MaybeInstallSigaction(int signum, 61 void (*handler)(int, siginfo_t *, void *)) { 62 if (!AsanInterceptsSignal(signum)) 63 return; 64 struct sigaction sigact; 65 REAL(memset)(&sigact, 0, sizeof(sigact)); 66 sigact.sa_sigaction = handler; 67 sigact.sa_flags = SA_SIGINFO; 68 if (FLAG_use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; 69 CHECK(0 == REAL(sigaction)(signum, &sigact, 0)); 70 if (FLAG_v >= 1) { 71 Report("Installed the sigaction for signal %d\n", signum); 72 } 73} 74 75static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { 76 uptr addr = (uptr)siginfo->si_addr; 77 // Write the first message using the bullet-proof write. 78 if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); 79 uptr pc, sp, bp; 80 GetPcSpBp(context, &pc, &sp, &bp); 81 AsanReport("ERROR: AddressSanitizer crashed on unknown address %p" 82 " (pc %p sp %p bp %p T%d)\n", 83 (void*)addr, (void*)pc, (void*)sp, (void*)bp, 84 asanThreadRegistry().GetCurrentTidOrInvalid()); 85 AsanPrintf("AddressSanitizer can not provide additional info. ABORTING\n"); 86 GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); 87 stack.PrintStack(); 88 ShowStatsAndAbort(); 89} 90 91void SetAlternateSignalStack() { 92 stack_t altstack, oldstack; 93 CHECK(0 == sigaltstack(0, &oldstack)); 94 // If the alternate stack is already in place, do nothing. 95 if ((oldstack.ss_flags & SS_DISABLE) == 0) return; 96 // TODO(glider): the mapped stack should have the MAP_STACK flag in the 97 // future. It is not required by man 2 sigaltstack now (they're using 98 // malloc()). 99 void* base = MmapOrDie(kAltStackSize, __FUNCTION__); 100 altstack.ss_sp = base; 101 altstack.ss_flags = 0; 102 altstack.ss_size = kAltStackSize; 103 CHECK(0 == sigaltstack(&altstack, 0)); 104 if (FLAG_v > 0) { 105 Report("Alternative stack for T%d set: [%p,%p)\n", 106 asanThreadRegistry().GetCurrentTidOrInvalid(), 107 altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); 108 } 109} 110 111void UnsetAlternateSignalStack() { 112 stack_t altstack, oldstack; 113 altstack.ss_sp = 0; 114 altstack.ss_flags = SS_DISABLE; 115 altstack.ss_size = 0; 116 CHECK(0 == sigaltstack(&altstack, &oldstack)); 117 UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); 118} 119 120void InstallSignalHandlers() { 121 // Set the alternate signal stack for the main thread. 122 // This will cause SetAlternateSignalStack to be called twice, but the stack 123 // will be actually set only once. 124 if (FLAG_use_sigaltstack) SetAlternateSignalStack(); 125 MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); 126 MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); 127} 128 129// ---------------------- TSD ---------------- {{{1 130 131static pthread_key_t tsd_key; 132static bool tsd_key_inited = false; 133void AsanTSDInit(void (*destructor)(void *tsd)) { 134 CHECK(!tsd_key_inited); 135 tsd_key_inited = true; 136 CHECK(0 == pthread_key_create(&tsd_key, destructor)); 137} 138 139void *AsanTSDGet() { 140 CHECK(tsd_key_inited); 141 return pthread_getspecific(tsd_key); 142} 143 144void AsanTSDSet(void *tsd) { 145 CHECK(tsd_key_inited); 146 pthread_setspecific(tsd_key, tsd); 147} 148 149} // namespace __asan 150 151#endif // __linux__ || __APPLE_ 152