Sergey Matveev | e86e35f | 2013-10-14 12:01:05 +0000 | [diff] [blame] | 1 | //===-- asan_posix.cc -----------------------------------------------------===// |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// |
Evgeniy Stepanov | 24e1372 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 14 | |
| 15 | #include "sanitizer_common/sanitizer_platform.h" |
| 16 | #if SANITIZER_LINUX || SANITIZER_MAC |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 17 | |
| 18 | #include "asan_internal.h" |
| 19 | #include "asan_interceptors.h" |
Evgeniy Stepanov | c99f700 | 2012-05-23 15:21:50 +0000 | [diff] [blame] | 20 | #include "asan_mapping.h" |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 21 | #include "asan_report.h" |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 22 | #include "asan_stack.h" |
Alexey Samsonov | 2221f55 | 2012-06-05 08:48:10 +0000 | [diff] [blame] | 23 | #include "sanitizer_common/sanitizer_libc.h" |
Alexey Samsonov | 6895adc | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 24 | #include "sanitizer_common/sanitizer_procmaps.h" |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 25 | |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 26 | #include <pthread.h> |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 27 | #include <signal.h> |
Alexey Samsonov | b823e3c | 2012-02-22 14:07:06 +0000 | [diff] [blame] | 28 | #include <stdlib.h> |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 29 | #include <sys/time.h> |
| 30 | #include <sys/resource.h> |
Kostya Serebryany | 0ecf5eb | 2012-01-09 23:11:26 +0000 | [diff] [blame] | 31 | #include <unistd.h> |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 32 | |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 33 | static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 34 | |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 35 | namespace __asan { |
| 36 | |
| 37 | static void MaybeInstallSigaction(int signum, |
| 38 | void (*handler)(int, siginfo_t *, void *)) { |
| 39 | if (!AsanInterceptsSignal(signum)) |
| 40 | return; |
| 41 | struct sigaction sigact; |
Alexey Samsonov | 09672ca | 2012-02-08 13:45:31 +0000 | [diff] [blame] | 42 | REAL(memset)(&sigact, 0, sizeof(sigact)); |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 43 | sigact.sa_sigaction = handler; |
| 44 | sigact.sa_flags = SA_SIGINFO; |
Alexey Samsonov | cb8c4dc | 2012-07-09 14:36:04 +0000 | [diff] [blame] | 45 | if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; |
Kostya Serebryany | a27bdf7 | 2013-04-05 14:40:25 +0000 | [diff] [blame] | 46 | CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0)); |
Dmitry Vyukov | 6866dba | 2013-10-15 13:28:51 +0000 | [diff] [blame] | 47 | if (common_flags()->verbosity >= 1) { |
Alexander Potapenko | a87bdaa | 2012-05-30 15:29:11 +0000 | [diff] [blame] | 48 | Report("Installed the sigaction for signal %d\n", signum); |
| 49 | } |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 50 | } |
| 51 | |
| 52 | static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 53 | uptr addr = (uptr)siginfo->si_addr; |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 54 | // Write the first message using the bullet-proof write. |
Alexey Samsonov | 47657ce | 2012-06-06 07:02:44 +0000 | [diff] [blame] | 55 | if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 56 | uptr pc, sp, bp; |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 57 | GetPcSpBp(context, &pc, &sp, &bp); |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 58 | ReportSIGSEGV(pc, sp, bp, addr); |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 59 | } |
| 60 | |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 61 | void SetAlternateSignalStack() { |
| 62 | stack_t altstack, oldstack; |
Kostya Serebryany | a27bdf7 | 2013-04-05 14:40:25 +0000 | [diff] [blame] | 63 | CHECK_EQ(0, sigaltstack(0, &oldstack)); |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 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()). |
Alexey Samsonov | a25b346 | 2012-06-06 16:15:07 +0000 | [diff] [blame] | 69 | void* base = MmapOrDie(kAltStackSize, __FUNCTION__); |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 70 | altstack.ss_sp = base; |
| 71 | altstack.ss_flags = 0; |
| 72 | altstack.ss_size = kAltStackSize; |
Kostya Serebryany | a27bdf7 | 2013-04-05 14:40:25 +0000 | [diff] [blame] | 73 | CHECK_EQ(0, sigaltstack(&altstack, 0)); |
Dmitry Vyukov | 6866dba | 2013-10-15 13:28:51 +0000 | [diff] [blame] | 74 | if (common_flags()->verbosity > 0) { |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 75 | Report("Alternative stack for T%d set: [%p,%p)\n", |
Alexey Samsonov | 89c1384 | 2013-03-20 09:23:28 +0000 | [diff] [blame] | 76 | GetCurrentTidOrInvalid(), |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 77 | altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | void UnsetAlternateSignalStack() { |
| 82 | stack_t altstack, oldstack; |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 83 | altstack.ss_sp = 0; |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 84 | altstack.ss_flags = SS_DISABLE; |
| 85 | altstack.ss_size = 0; |
Kostya Serebryany | a27bdf7 | 2013-04-05 14:40:25 +0000 | [diff] [blame] | 86 | CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); |
Alexey Samsonov | a25b346 | 2012-06-06 16:15:07 +0000 | [diff] [blame] | 87 | UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 88 | } |
| 89 | |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 90 | void InstallSignalHandlers() { |
Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 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. |
Alexey Samsonov | cb8c4dc | 2012-07-09 14:36:04 +0000 | [diff] [blame] | 94 | if (flags()->use_sigaltstack) SetAlternateSignalStack(); |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 95 | MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); |
| 96 | MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); |
| 97 | } |
| 98 | |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 99 | // ---------------------- TSD ---------------- {{{1 |
| 100 | |
| 101 | static pthread_key_t tsd_key; |
| 102 | static bool tsd_key_inited = false; |
Kostya Serebryany | f58f998 | 2012-02-07 00:27:15 +0000 | [diff] [blame] | 103 | void AsanTSDInit(void (*destructor)(void *tsd)) { |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 104 | CHECK(!tsd_key_inited); |
| 105 | tsd_key_inited = true; |
Kostya Serebryany | a27bdf7 | 2013-04-05 14:40:25 +0000 | [diff] [blame] | 106 | CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | void *AsanTSDGet() { |
| 110 | CHECK(tsd_key_inited); |
| 111 | return pthread_getspecific(tsd_key); |
| 112 | } |
| 113 | |
| 114 | void AsanTSDSet(void *tsd) { |
| 115 | CHECK(tsd_key_inited); |
| 116 | pthread_setspecific(tsd_key, tsd); |
| 117 | } |
| 118 | |
Sergey Matveev | e86e35f | 2013-10-14 12:01:05 +0000 | [diff] [blame] | 119 | void 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 Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 128 | } // namespace __asan |
| 129 | |
Alexey Samsonov | 649a270 | 2013-04-03 07:29:53 +0000 | [diff] [blame] | 130 | #endif // SANITIZER_LINUX || SANITIZER_MAC |