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