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