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