asan_posix.cc revision ee3925515e4c7966f3ef489f687aa7e5692806a9
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_procmaps.h" 20#include "asan_stack.h" 21#include "asan_thread_registry.h" 22 23#include <pthread.h> 24#include <signal.h> 25#include <stdlib.h> 26#include <sys/time.h> 27#include <sys/resource.h> 28#include <unistd.h> 29 30#ifdef ANDROID 31#include <sys/atomics.h> 32#endif 33 34// Should not add dependency on libstdc++, 35// since most of the stuff here is inlinable. 36#include <algorithm> 37 38static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. 39 40namespace __asan { 41 42static inline bool IntervalsAreSeparate(uptr start1, uptr end1, 43 uptr start2, uptr end2) { 44 CHECK(start1 <= end1); 45 CHECK(start2 <= end2); 46 return (end1 < start2) || (end2 < start1); 47} 48 49// FIXME: this is thread-unsafe, but should not cause problems most of the time. 50// When the shadow is mapped only a single thread usually exists (plus maybe 51// several worker threads on Mac, which aren't expected to map big chunks of 52// memory). 53bool AsanShadowRangeIsAvailable() { 54 AsanProcMaps procmaps; 55 uptr start, end; 56 uptr shadow_start = kLowShadowBeg; 57 if (kLowShadowBeg > 0) shadow_start -= kMmapGranularity; 58 uptr shadow_end = kHighShadowEnd; 59 while (procmaps.Next(&start, &end, 60 /*offset*/0, /*filename*/0, /*filename_size*/0)) { 61 if (!IntervalsAreSeparate(start, end, shadow_start, shadow_end)) 62 return false; 63 } 64 return true; 65} 66 67static void MaybeInstallSigaction(int signum, 68 void (*handler)(int, siginfo_t *, void *)) { 69 if (!AsanInterceptsSignal(signum)) 70 return; 71 struct sigaction sigact; 72 REAL(memset)(&sigact, 0, sizeof(sigact)); 73 sigact.sa_sigaction = handler; 74 sigact.sa_flags = SA_SIGINFO; 75 if (FLAG_use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; 76 CHECK(0 == REAL(sigaction)(signum, &sigact, 0)); 77 if (FLAG_v >= 1) { 78 Report("Installed the sigaction for signal %d\n", signum); 79 } 80} 81 82static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { 83 uptr addr = (uptr)siginfo->si_addr; 84 // Write the first message using the bullet-proof write. 85 if (13 != AsanWrite(2, "ASAN:SIGSEGV\n", 13)) AsanDie(); 86 uptr pc, sp, bp; 87 GetPcSpBp(context, &pc, &sp, &bp); 88 Report("ERROR: AddressSanitizer crashed on unknown address %p" 89 " (pc %p sp %p bp %p T%d)\n", 90 addr, pc, sp, bp, 91 asanThreadRegistry().GetCurrentTidOrMinusOne()); 92 Printf("AddressSanitizer can not provide additional info. ABORTING\n"); 93 GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); 94 stack.PrintStack(); 95 ShowStatsAndAbort(); 96} 97 98void SetAlternateSignalStack() { 99 stack_t altstack, oldstack; 100 CHECK(0 == sigaltstack(0, &oldstack)); 101 // If the alternate stack is already in place, do nothing. 102 if ((oldstack.ss_flags & SS_DISABLE) == 0) return; 103 // TODO(glider): the mapped stack should have the MAP_STACK flag in the 104 // future. It is not required by man 2 sigaltstack now (they're using 105 // malloc()). 106 void* base = AsanMmapSomewhereOrDie(kAltStackSize, __FUNCTION__); 107 altstack.ss_sp = base; 108 altstack.ss_flags = 0; 109 altstack.ss_size = kAltStackSize; 110 CHECK(0 == sigaltstack(&altstack, 0)); 111 if (FLAG_v > 0) { 112 Report("Alternative stack for T%d set: [%p,%p)\n", 113 asanThreadRegistry().GetCurrentTidOrMinusOne(), 114 altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); 115 } 116} 117 118void UnsetAlternateSignalStack() { 119 stack_t altstack, oldstack; 120 altstack.ss_sp = 0; 121 altstack.ss_flags = SS_DISABLE; 122 altstack.ss_size = 0; 123 CHECK(0 == sigaltstack(&altstack, &oldstack)); 124 AsanUnmapOrDie(oldstack.ss_sp, oldstack.ss_size); 125} 126 127void InstallSignalHandlers() { 128 // Set the alternate signal stack for the main thread. 129 // This will cause SetAlternateSignalStack to be called twice, but the stack 130 // will be actually set only once. 131 if (FLAG_use_sigaltstack) SetAlternateSignalStack(); 132 MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); 133 MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); 134} 135 136void AsanDisableCoreDumper() { 137 struct rlimit nocore; 138 nocore.rlim_cur = 0; 139 nocore.rlim_max = 0; 140 setrlimit(RLIMIT_CORE, &nocore); 141} 142 143void AsanDumpProcessMap() { 144 AsanProcMaps proc_maps; 145 uptr start, end; 146 const sptr kBufSize = 4095; 147 char filename[kBufSize]; 148 Report("Process memory map follows:\n"); 149 while (proc_maps.Next(&start, &end, /* file_offset */0, 150 filename, kBufSize)) { 151 Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); 152 } 153 Report("End of process memory map.\n"); 154} 155 156int GetPid() { 157 return getpid(); 158} 159 160uptr GetThreadSelf() { 161 return (uptr)pthread_self(); 162} 163 164void SleepForSeconds(int seconds) { 165 sleep(seconds); 166} 167 168void Exit(int exitcode) { 169 _exit(exitcode); 170} 171 172void Abort() { 173 abort(); 174} 175 176int Atexit(void (*function)(void)) { 177 return atexit(function); 178} 179 180int AtomicInc(int *a) { 181#ifdef ANDROID 182 return __atomic_inc(a) + 1; 183#else 184 return __sync_add_and_fetch(a, 1); 185#endif 186} 187 188u16 AtomicExchange(u16 *a, u16 new_val) { 189 return __sync_lock_test_and_set(a, new_val); 190} 191 192void SortArray(uptr *array, uptr size) { 193 std::sort(array, array + size); 194} 195 196// ---------------------- TSD ---------------- {{{1 197 198static pthread_key_t tsd_key; 199static bool tsd_key_inited = false; 200void AsanTSDInit(void (*destructor)(void *tsd)) { 201 CHECK(!tsd_key_inited); 202 tsd_key_inited = true; 203 CHECK(0 == pthread_key_create(&tsd_key, destructor)); 204} 205 206void *AsanTSDGet() { 207 CHECK(tsd_key_inited); 208 return pthread_getspecific(tsd_key); 209} 210 211void AsanTSDSet(void *tsd) { 212 CHECK(tsd_key_inited); 213 pthread_setspecific(tsd_key, tsd); 214} 215 216} // namespace __asan 217 218#endif // __linux__ || __APPLE_ 219