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