//===-- asan_linux.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Posix-specific details. //===----------------------------------------------------------------------===// #if defined(__linux__) || defined(__APPLE__) #include "asan_internal.h" #include "asan_interceptors.h" #include "asan_procmaps.h" #include "asan_stack.h" #include "asan_thread_registry.h" #include #include #include #include #include #include #ifdef ANDROID #include #endif // Should not add dependency on libstdc++, // since most of the stuff here is inlinable. #include static const size_t kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. namespace __asan { static void MaybeInstallSigaction(int signum, void (*handler)(int, siginfo_t *, void *)) { if (!AsanInterceptsSignal(signum)) return; struct sigaction sigact; REAL(memset)(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = handler; sigact.sa_flags = SA_SIGINFO; if (FLAG_use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK(0 == REAL(sigaction)(signum, &sigact, 0)); } static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { uintptr_t addr = (uintptr_t)siginfo->si_addr; // Write the first message using the bullet-proof write. if (13 != AsanWrite(2, "ASAN:SIGSEGV\n", 13)) AsanDie(); uintptr_t pc, sp, bp; GetPcSpBp(context, &pc, &sp, &bp); Report("ERROR: AddressSanitizer crashed on unknown address %p" " (pc %p sp %p bp %p T%d)\n", addr, pc, sp, bp, asanThreadRegistry().GetCurrentTidOrMinusOne()); Printf("AddressSanitizer can not provide additional info. ABORTING\n"); GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); stack.PrintStack(); ShowStatsAndAbort(); } void SetAlternateSignalStack() { stack_t altstack, oldstack; CHECK(0 == sigaltstack(NULL, &oldstack)); // If the alternate stack is already in place, do nothing. if ((oldstack.ss_flags & SS_DISABLE) == 0) return; // TODO(glider): the mapped stack should have the MAP_STACK flag in the // future. It is not required by man 2 sigaltstack now (they're using // malloc()). void* base = AsanMmapSomewhereOrDie(kAltStackSize, __FUNCTION__); altstack.ss_sp = base; altstack.ss_flags = 0; altstack.ss_size = kAltStackSize; CHECK(0 == sigaltstack(&altstack, NULL)); if (FLAG_v > 0) { Report("Alternative stack for T%d set: [%p,%p)\n", asanThreadRegistry().GetCurrentTidOrMinusOne(), altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); } } void UnsetAlternateSignalStack() { stack_t altstack, oldstack; altstack.ss_sp = NULL; altstack.ss_flags = SS_DISABLE; altstack.ss_size = 0; CHECK(0 == sigaltstack(&altstack, &oldstack)); AsanUnmapOrDie(oldstack.ss_sp, oldstack.ss_size); } void InstallSignalHandlers() { // Set the alternate signal stack for the main thread. // This will cause SetAlternateSignalStack to be called twice, but the stack // will be actually set only once. if (FLAG_use_sigaltstack) SetAlternateSignalStack(); MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); } void AsanDisableCoreDumper() { struct rlimit nocore; nocore.rlim_cur = 0; nocore.rlim_max = 0; setrlimit(RLIMIT_CORE, &nocore); } void AsanDumpProcessMap() { AsanProcMaps proc_maps; uintptr_t start, end; const intptr_t kBufSize = 4095; char filename[kBufSize]; Report("Process memory map follows:\n"); while (proc_maps.Next(&start, &end, /* file_offset */NULL, filename, kBufSize)) { Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); } Report("End of process memory map.\n"); } int GetPid() { return getpid(); } uintptr_t GetThreadSelf() { return (uintptr_t)pthread_self(); } void SleepForSeconds(int seconds) { sleep(seconds); } void Exit(int exitcode) { _exit(exitcode); } void Abort() { abort(); } int Atexit(void (*function)(void)) { return atexit(function); } int AtomicInc(int *a) { #ifdef ANDROID return __atomic_inc(a) + 1; #else return __sync_add_and_fetch(a, 1); #endif } uint16_t AtomicExchange(uint16_t *a, uint16_t new_val) { return __sync_lock_test_and_set(a, new_val); } void SortArray(uintptr_t *array, size_t size) { std::sort(array, array + size); } // ---------------------- TSD ---------------- {{{1 static pthread_key_t tsd_key; static bool tsd_key_inited = false; void AsanTSDInit(void (*destructor)(void *tsd)) { CHECK(!tsd_key_inited); tsd_key_inited = true; CHECK(0 == pthread_key_create(&tsd_key, destructor)); } void *AsanTSDGet() { CHECK(tsd_key_inited); return pthread_getspecific(tsd_key); } void AsanTSDSet(void *tsd) { CHECK(tsd_key_inited); pthread_setspecific(tsd_key, tsd); } } // namespace __asan #endif // __linux__ || __APPLE_