blob: 9fde9df4c3b41ff65ad902761cc23e39fc2d48f1 [file] [log] [blame]
Kostya Serebryanya7e760a2012-01-09 19:18:27 +00001//===-- 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"
Evgeniy Stepanovc99f7002012-05-23 15:21:50 +000018#include "asan_mapping.h"
Alexander Potapenko99d17eb2012-02-22 09:11:55 +000019#include "asan_procmaps.h"
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000020#include "asan_stack.h"
21#include "asan_thread_registry.h"
22
Kostya Serebryanycc4e6862012-01-11 02:21:06 +000023#include <pthread.h>
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000024#include <signal.h>
Alexey Samsonovb823e3c2012-02-22 14:07:06 +000025#include <stdlib.h>
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000026#include <sys/time.h>
27#include <sys/resource.h>
Kostya Serebryany0ecf5eb2012-01-09 23:11:26 +000028#include <unistd.h>
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000029
Kostya Serebryanydde7c332012-01-11 02:39:16 +000030#ifdef ANDROID
31#include <sys/atomics.h>
32#endif
33
Kostya Serebryany25c71782012-03-10 01:30:01 +000034// Should not add dependency on libstdc++,
35// since most of the stuff here is inlinable.
36#include <algorithm>
37
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000038static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000039
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000040namespace __asan {
41
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000042static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
43 uptr start2, uptr end2) {
Evgeniy Stepanovc99f7002012-05-23 15:21:50 +000044 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;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000055 uptr start, end;
56 uptr shadow_start = kLowShadowBeg;
Evgeniy Stepanovc99f7002012-05-23 15:21:50 +000057 if (kLowShadowBeg > 0) shadow_start -= kMmapGranularity;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000058 uptr shadow_end = kHighShadowEnd;
Evgeniy Stepanovc99f7002012-05-23 15:21:50 +000059 while (procmaps.Next(&start, &end,
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000060 /*offset*/0, /*filename*/0, /*filename_size*/0)) {
Evgeniy Stepanovc99f7002012-05-23 15:21:50 +000061 if (!IntervalsAreSeparate(start, end, shadow_start, shadow_end))
62 return false;
63 }
64 return true;
65}
66
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000067static void MaybeInstallSigaction(int signum,
68 void (*handler)(int, siginfo_t *, void *)) {
69 if (!AsanInterceptsSignal(signum))
70 return;
71 struct sigaction sigact;
Alexey Samsonov09672ca2012-02-08 13:45:31 +000072 REAL(memset)(&sigact, 0, sizeof(sigact));
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000073 sigact.sa_sigaction = handler;
74 sigact.sa_flags = SA_SIGINFO;
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000075 if (FLAG_use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
Alexey Samsonov09672ca2012-02-08 13:45:31 +000076 CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
Alexander Potapenkoa87bdaa2012-05-30 15:29:11 +000077 if (FLAG_v >= 1) {
78 Report("Installed the sigaction for signal %d\n", signum);
79 }
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000080}
81
82static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000083 uptr addr = (uptr)siginfo->si_addr;
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000084 // Write the first message using the bullet-proof write.
Kostya Serebryany0ecf5eb2012-01-09 23:11:26 +000085 if (13 != AsanWrite(2, "ASAN:SIGSEGV\n", 13)) AsanDie();
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000086 uptr pc, sp, bp;
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000087 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");
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +000093 GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000094 stack.PrintStack();
95 ShowStatsAndAbort();
96}
97
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000098void SetAlternateSignalStack() {
99 stack_t altstack, oldstack;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000100 CHECK(0 == sigaltstack(0, &oldstack));
Alexander Potapenkof03d8af2012-04-05 10:54:52 +0000101 // 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;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000110 CHECK(0 == sigaltstack(&altstack, 0));
Alexander Potapenkof03d8af2012-04-05 10:54:52 +0000111 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;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000120 altstack.ss_sp = 0;
Alexander Potapenkof03d8af2012-04-05 10:54:52 +0000121 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
Kostya Serebryanya7e760a2012-01-09 19:18:27 +0000127void InstallSignalHandlers() {
Alexander Potapenkof03d8af2012-04-05 10:54:52 +0000128 // 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();
Kostya Serebryanya7e760a2012-01-09 19:18:27 +0000132 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
Alexander Potapenko99d17eb2012-02-22 09:11:55 +0000143void AsanDumpProcessMap() {
144 AsanProcMaps proc_maps;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000145 uptr start, end;
Alexander Potapenko99d17eb2012-02-22 09:11:55 +0000146 const intptr_t kBufSize = 4095;
147 char filename[kBufSize];
148 Report("Process memory map follows:\n");
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000149 while (proc_maps.Next(&start, &end, /* file_offset */0,
Alexander Potapenko99d17eb2012-02-22 09:11:55 +0000150 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
Kostya Serebryany0ecf5eb2012-01-09 23:11:26 +0000156int GetPid() {
157 return getpid();
158}
159
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000160uptr GetThreadSelf() {
161 return (uptr)pthread_self();
Kostya Serebryanycc4e6862012-01-11 02:21:06 +0000162}
163
Kostya Serebryanye1fe0fd2012-02-13 21:24:29 +0000164void SleepForSeconds(int seconds) {
165 sleep(seconds);
166}
167
168void Exit(int exitcode) {
Timur Iskhodzhanovb55c88d2012-03-13 16:29:25 +0000169 _exit(exitcode);
Kostya Serebryanye1fe0fd2012-02-13 21:24:29 +0000170}
171
Kostya Serebryanyf8e6fee2012-04-06 01:27:11 +0000172void Abort() {
173 abort();
174}
175
Alexey Samsonovb823e3c2012-02-22 14:07:06 +0000176int Atexit(void (*function)(void)) {
177 return atexit(function);
178}
179
Kostya Serebryanydde7c332012-01-11 02:39:16 +0000180int 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
Kostya Serebryanyf1e82b82012-04-05 15:55:09 +0000188uint16_t AtomicExchange(uint16_t *a, uint16_t new_val) {
189 return __sync_lock_test_and_set(a, new_val);
190}
191
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000192void SortArray(uptr *array, uptr size) {
Kostya Serebryany25c71782012-03-10 01:30:01 +0000193 std::sort(array, array + size);
194}
195
Kostya Serebryanycc4e6862012-01-11 02:21:06 +0000196// ---------------------- TSD ---------------- {{{1
197
198static pthread_key_t tsd_key;
199static bool tsd_key_inited = false;
Kostya Serebryanyf58f9982012-02-07 00:27:15 +0000200void AsanTSDInit(void (*destructor)(void *tsd)) {
Kostya Serebryanycc4e6862012-01-11 02:21:06 +0000201 CHECK(!tsd_key_inited);
202 tsd_key_inited = true;
Kostya Serebryanyf58f9982012-02-07 00:27:15 +0000203 CHECK(0 == pthread_key_create(&tsd_key, destructor));
Kostya Serebryanycc4e6862012-01-11 02:21:06 +0000204}
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
Kostya Serebryanya7e760a2012-01-09 19:18:27 +0000216} // namespace __asan
217
218#endif // __linux__ || __APPLE_