1 //===-- asan_posix.cc -----------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of AddressSanitizer, an address sanity checker.
10 // Posix-specific details.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
14 #if SANITIZER_LINUX || SANITIZER_MAC
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 "sanitizer_common/sanitizer_libc.h"
22 #include "sanitizer_common/sanitizer_procmaps.h"
28 #include <sys/resource.h>
31 static const uptr kAltStackSize
= SIGSTKSZ
* 4; // SIGSTKSZ is not enough.
35 static void MaybeInstallSigaction(int signum
,
36 void (*handler
)(int, siginfo_t
*, void *)) {
37 if (!AsanInterceptsSignal(signum
))
39 struct sigaction sigact
;
40 REAL(memset
)(&sigact
, 0, sizeof(sigact
));
41 sigact
.sa_sigaction
= handler
;
42 sigact
.sa_flags
= SA_SIGINFO
;
43 if (flags()->use_sigaltstack
) sigact
.sa_flags
|= SA_ONSTACK
;
44 CHECK_EQ(0, REAL(sigaction
)(signum
, &sigact
, 0));
45 if (common_flags()->verbosity
>= 1) {
46 Report("Installed the sigaction for signal %d\n", signum
);
50 static void ASAN_OnSIGSEGV(int, siginfo_t
*siginfo
, void *context
) {
51 uptr addr
= (uptr
)siginfo
->si_addr
;
52 // Write the first message using the bullet-proof write.
53 if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
55 GetPcSpBp(context
, &pc
, &sp
, &bp
);
56 ReportSIGSEGV(pc
, sp
, bp
, addr
);
59 void SetAlternateSignalStack() {
60 stack_t altstack
, oldstack
;
61 CHECK_EQ(0, sigaltstack(0, &oldstack
));
62 // If the alternate stack is already in place, do nothing.
63 if ((oldstack
.ss_flags
& SS_DISABLE
) == 0) return;
64 // TODO(glider): the mapped stack should have the MAP_STACK flag in the
65 // future. It is not required by man 2 sigaltstack now (they're using
67 void* base
= MmapOrDie(kAltStackSize
, __FUNCTION__
);
68 altstack
.ss_sp
= base
;
69 altstack
.ss_flags
= 0;
70 altstack
.ss_size
= kAltStackSize
;
71 CHECK_EQ(0, sigaltstack(&altstack
, 0));
72 if (common_flags()->verbosity
> 0) {
73 Report("Alternative stack for T%d set: [%p,%p)\n",
74 GetCurrentTidOrInvalid(),
75 altstack
.ss_sp
, (char*)altstack
.ss_sp
+ altstack
.ss_size
);
79 void UnsetAlternateSignalStack() {
80 stack_t altstack
, oldstack
;
82 altstack
.ss_flags
= SS_DISABLE
;
84 CHECK_EQ(0, sigaltstack(&altstack
, &oldstack
));
85 UnmapOrDie(oldstack
.ss_sp
, oldstack
.ss_size
);
88 void InstallSignalHandlers() {
89 // Set the alternate signal stack for the main thread.
90 // This will cause SetAlternateSignalStack to be called twice, but the stack
91 // will be actually set only once.
92 if (flags()->use_sigaltstack
) SetAlternateSignalStack();
93 MaybeInstallSigaction(SIGSEGV
, ASAN_OnSIGSEGV
);
94 MaybeInstallSigaction(SIGBUS
, ASAN_OnSIGSEGV
);
97 // ---------------------- TSD ---------------- {{{1
99 static pthread_key_t tsd_key
;
100 static bool tsd_key_inited
= false;
101 void AsanTSDInit(void (*destructor
)(void *tsd
)) {
102 CHECK(!tsd_key_inited
);
103 tsd_key_inited
= true;
104 CHECK_EQ(0, pthread_key_create(&tsd_key
, destructor
));
108 CHECK(tsd_key_inited
);
109 return pthread_getspecific(tsd_key
);
112 void AsanTSDSet(void *tsd
) {
113 CHECK(tsd_key_inited
);
114 pthread_setspecific(tsd_key
, tsd
);
117 void PlatformTSDDtor(void *tsd
) {
118 AsanThreadContext
*context
= (AsanThreadContext
*)tsd
;
119 if (context
->destructor_iterations
> 1) {
120 context
->destructor_iterations
--;
121 CHECK_EQ(0, pthread_setspecific(tsd_key
, tsd
));
124 AsanThread::TSDDtor(tsd
);
126 } // namespace __asan
128 #endif // SANITIZER_LINUX || SANITIZER_MAC