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