blob: bcc6b381a785123328d831757da3a17efd00ea5d [file] [log] [blame]
Sergey Matveeve86e35f2013-10-14 12:01:05 +00001//===-- asan_posix.cc -----------------------------------------------------===//
Kostya Serebryanya7e760a2012-01-09 19:18:27 +00002//
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//===----------------------------------------------------------------------===//
Evgeniy Stepanov24e13722013-03-19 14:33:38 +000014
15#include "sanitizer_common/sanitizer_platform.h"
16#if SANITIZER_LINUX || SANITIZER_MAC
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000017
18#include "asan_internal.h"
19#include "asan_interceptors.h"
Evgeniy Stepanovc99f7002012-05-23 15:21:50 +000020#include "asan_mapping.h"
Alexey Samsonov73545092012-08-09 07:40:58 +000021#include "asan_report.h"
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000022#include "asan_stack.h"
Alexey Samsonov2221f552012-06-05 08:48:10 +000023#include "sanitizer_common/sanitizer_libc.h"
Alexey Samsonov6895adc2012-06-07 06:15:12 +000024#include "sanitizer_common/sanitizer_procmaps.h"
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000025
Kostya Serebryanycc4e6862012-01-11 02:21:06 +000026#include <pthread.h>
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000027#include <signal.h>
Alexey Samsonovb823e3c2012-02-22 14:07:06 +000028#include <stdlib.h>
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000029#include <sys/time.h>
30#include <sys/resource.h>
Kostya Serebryany0ecf5eb2012-01-09 23:11:26 +000031#include <unistd.h>
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000032
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000033static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000034
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000035namespace __asan {
36
37static void MaybeInstallSigaction(int signum,
38 void (*handler)(int, siginfo_t *, void *)) {
39 if (!AsanInterceptsSignal(signum))
40 return;
41 struct sigaction sigact;
Alexey Samsonov09672ca2012-02-08 13:45:31 +000042 REAL(memset)(&sigact, 0, sizeof(sigact));
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000043 sigact.sa_sigaction = handler;
44 sigact.sa_flags = SA_SIGINFO;
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +000045 if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
Kostya Serebryanya27bdf72013-04-05 14:40:25 +000046 CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
Dmitry Vyukov6866dba2013-10-15 13:28:51 +000047 if (common_flags()->verbosity >= 1) {
Alexander Potapenkoa87bdaa2012-05-30 15:29:11 +000048 Report("Installed the sigaction for signal %d\n", signum);
49 }
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000050}
51
52static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000053 uptr addr = (uptr)siginfo->si_addr;
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000054 // Write the first message using the bullet-proof write.
Alexey Samsonov47657ce2012-06-06 07:02:44 +000055 if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000056 uptr pc, sp, bp;
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000057 GetPcSpBp(context, &pc, &sp, &bp);
Alexey Samsonov73545092012-08-09 07:40:58 +000058 ReportSIGSEGV(pc, sp, bp, addr);
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000059}
60
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000061void SetAlternateSignalStack() {
62 stack_t altstack, oldstack;
Kostya Serebryanya27bdf72013-04-05 14:40:25 +000063 CHECK_EQ(0, sigaltstack(0, &oldstack));
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000064 // 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()).
Alexey Samsonova25b3462012-06-06 16:15:07 +000069 void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000070 altstack.ss_sp = base;
71 altstack.ss_flags = 0;
72 altstack.ss_size = kAltStackSize;
Kostya Serebryanya27bdf72013-04-05 14:40:25 +000073 CHECK_EQ(0, sigaltstack(&altstack, 0));
Dmitry Vyukov6866dba2013-10-15 13:28:51 +000074 if (common_flags()->verbosity > 0) {
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000075 Report("Alternative stack for T%d set: [%p,%p)\n",
Alexey Samsonov89c13842013-03-20 09:23:28 +000076 GetCurrentTidOrInvalid(),
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000077 altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
78 }
79}
80
81void UnsetAlternateSignalStack() {
82 stack_t altstack, oldstack;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000083 altstack.ss_sp = 0;
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000084 altstack.ss_flags = SS_DISABLE;
85 altstack.ss_size = 0;
Kostya Serebryanya27bdf72013-04-05 14:40:25 +000086 CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
Alexey Samsonova25b3462012-06-06 16:15:07 +000087 UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000088}
89
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000090void InstallSignalHandlers() {
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000091 // 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.
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +000094 if (flags()->use_sigaltstack) SetAlternateSignalStack();
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000095 MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
96 MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
97}
98
Kostya Serebryanycc4e6862012-01-11 02:21:06 +000099// ---------------------- TSD ---------------- {{{1
100
101static pthread_key_t tsd_key;
102static bool tsd_key_inited = false;
Kostya Serebryanyf58f9982012-02-07 00:27:15 +0000103void AsanTSDInit(void (*destructor)(void *tsd)) {
Kostya Serebryanycc4e6862012-01-11 02:21:06 +0000104 CHECK(!tsd_key_inited);
105 tsd_key_inited = true;
Kostya Serebryanya27bdf72013-04-05 14:40:25 +0000106 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
Kostya Serebryanycc4e6862012-01-11 02:21:06 +0000107}
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
Sergey Matveeve86e35f2013-10-14 12:01:05 +0000119void 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}
Kostya Serebryanya7e760a2012-01-09 19:18:27 +0000128} // namespace __asan
129
Alexey Samsonov649a2702013-04-03 07:29:53 +0000130#endif // SANITIZER_LINUX || SANITIZER_MAC