Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 1 | //===-- msan_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 MemorySanitizer. |
| 11 | // |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 12 | // Linux- and FreeBSD-specific code. |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 13 | //===----------------------------------------------------------------------===// |
| 14 | |
Evgeniy Stepanov | 0af6723 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 15 | #include "sanitizer_common/sanitizer_platform.h" |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 16 | #if SANITIZER_FREEBSD || SANITIZER_LINUX |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 17 | |
| 18 | #include "msan.h" |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 19 | #include "msan_thread.h" |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 20 | |
Reid Kleckner | c9d382b | 2013-03-11 18:07:42 +0000 | [diff] [blame] | 21 | #include <elf.h> |
| 22 | #include <link.h> |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 23 | #include <pthread.h> |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 24 | #include <stdio.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <signal.h> |
| 27 | #include <unistd.h> |
| 28 | #include <unwind.h> |
| 29 | #include <execinfo.h> |
| 30 | #include <sys/time.h> |
| 31 | #include <sys/resource.h> |
| 32 | |
| 33 | #include "sanitizer_common/sanitizer_common.h" |
| 34 | #include "sanitizer_common/sanitizer_procmaps.h" |
| 35 | |
| 36 | namespace __msan { |
| 37 | |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 38 | void ReportMapRange(const char *descr, uptr beg, uptr size) { |
| 39 | if (size > 0) { |
| 40 | uptr end = beg + size - 1; |
| 41 | VPrintf(1, "%s : %p - %p\n", descr, beg, end); |
Evgeniy Stepanov | bfdb9b2 | 2013-11-11 09:27:20 +0000 | [diff] [blame] | 42 | } |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 43 | } |
Evgeniy Stepanov | bfdb9b2 | 2013-11-11 09:27:20 +0000 | [diff] [blame] | 44 | |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 45 | static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { |
| 46 | if (size > 0) { |
| 47 | uptr end = beg + size - 1; |
| 48 | if (!MemoryRangeIsAvailable(beg, end)) { |
| 49 | Printf("FATAL: Memory range %p - %p is not available.\n", beg, end); |
| 50 | return false; |
| 51 | } |
| 52 | } |
| 53 | return true; |
| 54 | } |
| 55 | |
Evgeniy Stepanov | 8e9c70b | 2015-05-29 22:31:28 +0000 | [diff] [blame] | 56 | static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 57 | if (size > 0) { |
Evgeniy Stepanov | 8e9c70b | 2015-05-29 22:31:28 +0000 | [diff] [blame] | 58 | void *addr = MmapNoAccess(beg, size, name); |
Vedant Kumar | 59ba7b8 | 2015-10-01 00:22:21 +0000 | [diff] [blame] | 59 | if (beg == 0 && addr) { |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 60 | // Depending on the kernel configuration, we may not be able to protect |
| 61 | // the page at address zero. |
| 62 | uptr gap = 16 * GetPageSizeCached(); |
| 63 | beg += gap; |
| 64 | size -= gap; |
Evgeniy Stepanov | 8e9c70b | 2015-05-29 22:31:28 +0000 | [diff] [blame] | 65 | addr = MmapNoAccess(beg, size, name); |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 66 | } |
| 67 | if ((uptr)addr != beg) { |
| 68 | uptr end = beg + size - 1; |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 69 | Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end); |
| 70 | return false; |
| 71 | } |
| 72 | } |
| 73 | return true; |
| 74 | } |
| 75 | |
Evgeniy Stepanov | 8441bb2 | 2015-01-27 13:20:34 +0000 | [diff] [blame] | 76 | static void CheckMemoryLayoutSanity() { |
| 77 | uptr prev_end = 0; |
| 78 | for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { |
| 79 | uptr start = kMemoryLayout[i].start; |
| 80 | uptr end = kMemoryLayout[i].end; |
| 81 | MappingDesc::Type type = kMemoryLayout[i].type; |
| 82 | CHECK_LT(start, end); |
| 83 | CHECK_EQ(prev_end, start); |
| 84 | CHECK(addr_is_type(start, type)); |
| 85 | CHECK(addr_is_type((start + end) / 2, type)); |
| 86 | CHECK(addr_is_type(end - 1, type)); |
| 87 | if (type == MappingDesc::APP) { |
| 88 | uptr addr = start; |
| 89 | CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); |
| 90 | CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); |
| 91 | CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); |
| 92 | |
| 93 | addr = (start + end) / 2; |
| 94 | CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); |
| 95 | CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); |
| 96 | CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); |
| 97 | |
| 98 | addr = end - 1; |
| 99 | CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); |
| 100 | CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); |
| 101 | CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); |
| 102 | } |
| 103 | prev_end = end; |
| 104 | } |
| 105 | } |
| 106 | |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 107 | bool InitShadow(bool init_origins) { |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 108 | // Let user know mapping parameters first. |
Sergey Matveev | 9be70fb | 2013-12-05 12:04:51 +0000 | [diff] [blame] | 109 | VPrintf(1, "__msan_init %p\n", &__msan_init); |
Evgeniy Stepanov | 8441bb2 | 2015-01-27 13:20:34 +0000 | [diff] [blame] | 110 | for (unsigned i = 0; i < kMemoryLayoutSize; ++i) |
| 111 | VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, |
| 112 | kMemoryLayout[i].end - 1); |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 113 | |
Evgeniy Stepanov | 8441bb2 | 2015-01-27 13:20:34 +0000 | [diff] [blame] | 114 | CheckMemoryLayoutSanity(); |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 115 | |
| 116 | if (!MEM_IS_APP(&__msan_init)) { |
| 117 | Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", |
| 118 | (uptr)&__msan_init); |
Evgeniy Stepanov | 794a731 | 2012-12-26 06:37:23 +0000 | [diff] [blame] | 119 | return false; |
| 120 | } |
| 121 | |
Evgeniy Stepanov | 8441bb2 | 2015-01-27 13:20:34 +0000 | [diff] [blame] | 122 | for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { |
| 123 | uptr start = kMemoryLayout[i].start; |
| 124 | uptr end = kMemoryLayout[i].end; |
| 125 | uptr size= end - start; |
| 126 | MappingDesc::Type type = kMemoryLayout[i].type; |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 127 | |
| 128 | bool map = type == MappingDesc::SHADOW || |
| 129 | (init_origins && type == MappingDesc::ORIGIN); |
| 130 | bool protect = type == MappingDesc::INVALID || |
| 131 | (!init_origins && type == MappingDesc::ORIGIN); |
| 132 | CHECK(!(map && protect)); |
| 133 | if (!map && !protect) |
| 134 | CHECK(type == MappingDesc::APP); |
| 135 | if (map) { |
| 136 | if (!CheckMemoryRangeAvailability(start, size)) |
| 137 | return false; |
Evgeniy Stepanov | 8e9c70b | 2015-05-29 22:31:28 +0000 | [diff] [blame] | 138 | if ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start) |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 139 | return false; |
Yury Gribov | 8f848ff | 2015-02-03 10:15:15 +0000 | [diff] [blame] | 140 | if (common_flags()->use_madv_dontdump) |
| 141 | DontDumpShadowMemory(start, size); |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 142 | } |
| 143 | if (protect) { |
| 144 | if (!CheckMemoryRangeAvailability(start, size)) |
| 145 | return false; |
Evgeniy Stepanov | 8e9c70b | 2015-05-29 22:31:28 +0000 | [diff] [blame] | 146 | if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name)) |
Evgeniy Stepanov | 4532824 | 2015-05-24 02:47:59 +0000 | [diff] [blame] | 147 | return false; |
Evgeniy Stepanov | 8441bb2 | 2015-01-27 13:20:34 +0000 | [diff] [blame] | 148 | } |
Viktor Kutuzov | 30bd345 | 2014-11-28 11:42:55 +0000 | [diff] [blame] | 149 | } |
| 150 | |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 151 | return true; |
| 152 | } |
| 153 | |
Evgeniy Stepanov | 9b52ce9 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 154 | static void MsanAtExit(void) { |
Evgeniy Stepanov | ad8065f | 2014-06-24 09:04:06 +0000 | [diff] [blame] | 155 | if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) |
| 156 | ReportStats(); |
Evgeniy Stepanov | 9b52ce9 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 157 | if (msan_report_count > 0) { |
| 158 | ReportAtExitStatistics(); |
Alexey Samsonov | bb79b06 | 2015-08-21 20:49:37 +0000 | [diff] [blame] | 159 | if (common_flags()->exitcode) |
| 160 | internal__exit(common_flags()->exitcode); |
Evgeniy Stepanov | 9b52ce9 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 161 | } |
| 162 | } |
| 163 | |
| 164 | void InstallAtExitHandler() { |
| 165 | atexit(MsanAtExit); |
| 166 | } |
Reid Kleckner | c9d382b | 2013-03-11 18:07:42 +0000 | [diff] [blame] | 167 | |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 168 | // ---------------------- TSD ---------------- {{{1 |
| 169 | |
| 170 | static pthread_key_t tsd_key; |
| 171 | static bool tsd_key_inited = false; |
Evgeniy Stepanov | 372deb0 | 2014-12-17 10:30:06 +0000 | [diff] [blame] | 172 | |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 173 | void MsanTSDInit(void (*destructor)(void *tsd)) { |
| 174 | CHECK(!tsd_key_inited); |
| 175 | tsd_key_inited = true; |
| 176 | CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); |
| 177 | } |
| 178 | |
Evgeniy Stepanov | 372deb0 | 2014-12-17 10:30:06 +0000 | [diff] [blame] | 179 | static THREADLOCAL MsanThread* msan_current_thread; |
| 180 | |
| 181 | MsanThread *GetCurrentThread() { |
| 182 | return msan_current_thread; |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 183 | } |
| 184 | |
Evgeniy Stepanov | 372deb0 | 2014-12-17 10:30:06 +0000 | [diff] [blame] | 185 | void SetCurrentThread(MsanThread *t) { |
| 186 | // Make sure we do not reset the current MsanThread. |
| 187 | CHECK_EQ(0, msan_current_thread); |
| 188 | msan_current_thread = t; |
| 189 | // Make sure that MsanTSDDtor gets called at the end. |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 190 | CHECK(tsd_key_inited); |
Evgeniy Stepanov | 372deb0 | 2014-12-17 10:30:06 +0000 | [diff] [blame] | 191 | pthread_setspecific(tsd_key, (void *)t); |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | void MsanTSDDtor(void *tsd) { |
| 195 | MsanThread *t = (MsanThread*)tsd; |
| 196 | if (t->destructor_iterations_ > 1) { |
| 197 | t->destructor_iterations_--; |
| 198 | CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); |
| 199 | return; |
| 200 | } |
Evgeniy Stepanov | 372deb0 | 2014-12-17 10:30:06 +0000 | [diff] [blame] | 201 | msan_current_thread = nullptr; |
| 202 | // Make sure that signal handler can not see a stale current thread pointer. |
| 203 | atomic_signal_fence(memory_order_seq_cst); |
Evgeniy Stepanov | f653cda | 2014-04-04 09:47:41 +0000 | [diff] [blame] | 204 | MsanThread::TSDDtor(tsd); |
| 205 | } |
| 206 | |
Vedant Kumar | 59ba7b8 | 2015-10-01 00:22:21 +0000 | [diff] [blame] | 207 | } // namespace __msan |
Evgeniy Stepanov | c503378 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 208 | |
Vedant Kumar | 59ba7b8 | 2015-10-01 00:22:21 +0000 | [diff] [blame] | 209 | #endif // SANITIZER_FREEBSD || SANITIZER_LINUX |