asan_posix.cc revision f3950c6d6acf53fe60735f6d38715c1ea6df814b
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_report.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
32static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
33
34namespace __asan {
35
36static void MaybeInstallSigaction(int signum,
37                                  void (*handler)(int, siginfo_t *, void *)) {
38  if (!AsanInterceptsSignal(signum))
39    return;
40  struct sigaction sigact;
41  REAL(memset)(&sigact, 0, sizeof(sigact));
42  sigact.sa_sigaction = handler;
43  sigact.sa_flags = SA_SIGINFO;
44  if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
45  CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
46  if (flags()->verbosity >= 1) {
47    Report("Installed the sigaction for signal %d\n", signum);
48  }
49}
50
51static void     ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
52  uptr addr = (uptr)siginfo->si_addr;
53  // Write the first message using the bullet-proof write.
54  if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
55  uptr pc, sp, bp;
56  GetPcSpBp(context, &pc, &sp, &bp);
57  ReportSIGSEGV(pc, sp, bp, addr);
58}
59
60void SetAlternateSignalStack() {
61  stack_t altstack, oldstack;
62  CHECK(0 == sigaltstack(0, &oldstack));
63  // If the alternate stack is already in place, do nothing.
64  if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
65  // TODO(glider): the mapped stack should have the MAP_STACK flag in the
66  // future. It is not required by man 2 sigaltstack now (they're using
67  // malloc()).
68  void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
69  altstack.ss_sp = base;
70  altstack.ss_flags = 0;
71  altstack.ss_size = kAltStackSize;
72  CHECK(0 == sigaltstack(&altstack, 0));
73  if (flags()->verbosity > 0) {
74    Report("Alternative stack for T%d set: [%p,%p)\n",
75           asanThreadRegistry().GetCurrentTidOrInvalid(),
76           altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
77  }
78}
79
80void UnsetAlternateSignalStack() {
81  stack_t altstack, oldstack;
82  altstack.ss_sp = 0;
83  altstack.ss_flags = SS_DISABLE;
84  altstack.ss_size = 0;
85  CHECK(0 == sigaltstack(&altstack, &oldstack));
86  UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
87}
88
89void InstallSignalHandlers() {
90  // Set the alternate signal stack for the main thread.
91  // This will cause SetAlternateSignalStack to be called twice, but the stack
92  // will be actually set only once.
93  if (flags()->use_sigaltstack) SetAlternateSignalStack();
94  MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
95  MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
96}
97
98// ---------------------- TSD ---------------- {{{1
99
100static pthread_key_t tsd_key;
101static bool tsd_key_inited = false;
102void AsanTSDInit(void (*destructor)(void *tsd)) {
103  CHECK(!tsd_key_inited);
104  tsd_key_inited = true;
105  CHECK(0 == pthread_key_create(&tsd_key, destructor));
106}
107
108void *AsanTSDGet() {
109  CHECK(tsd_key_inited);
110  return pthread_getspecific(tsd_key);
111}
112
113void AsanTSDSet(void *tsd) {
114  CHECK(tsd_key_inited);
115  pthread_setspecific(tsd_key, tsd);
116}
117
118}  // namespace __asan
119
120#endif  // __linux__ || __APPLE_
121