blob: 2888eb528d13b07957615b1d0fa67ad572eeb62f [file] [log] [blame]
Evgeniy Stepanovc5033782012-12-11 12:27:27 +00001//===-- 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 Kutuzov30bd3452014-11-28 11:42:55 +000012// Linux- and FreeBSD-specific code.
Evgeniy Stepanovc5033782012-12-11 12:27:27 +000013//===----------------------------------------------------------------------===//
14
Evgeniy Stepanov0af67232013-03-19 14:33:38 +000015#include "sanitizer_common/sanitizer_platform.h"
Viktor Kutuzov30bd3452014-11-28 11:42:55 +000016#if SANITIZER_FREEBSD || SANITIZER_LINUX
Evgeniy Stepanovc5033782012-12-11 12:27:27 +000017
18#include "msan.h"
Evgeniy Stepanovf653cda2014-04-04 09:47:41 +000019#include "msan_thread.h"
Evgeniy Stepanovc5033782012-12-11 12:27:27 +000020
Reid Klecknerc9d382b2013-03-11 18:07:42 +000021#include <elf.h>
22#include <link.h>
Evgeniy Stepanovf653cda2014-04-04 09:47:41 +000023#include <pthread.h>
Evgeniy Stepanovc5033782012-12-11 12:27:27 +000024#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
36namespace __msan {
37
Viktor Kutuzov30bd3452014-11-28 11:42:55 +000038void 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 Stepanovbfdb9b22013-11-11 09:27:20 +000042 }
Viktor Kutuzov30bd3452014-11-28 11:42:55 +000043}
Evgeniy Stepanovbfdb9b22013-11-11 09:27:20 +000044
Viktor Kutuzov30bd3452014-11-28 11:42:55 +000045static 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 Stepanov8e9c70b2015-05-29 22:31:28 +000056static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
Viktor Kutuzov30bd3452014-11-28 11:42:55 +000057 if (size > 0) {
Evgeniy Stepanov8e9c70b2015-05-29 22:31:28 +000058 void *addr = MmapNoAccess(beg, size, name);
Vedant Kumar59ba7b82015-10-01 00:22:21 +000059 if (beg == 0 && addr) {
Evgeniy Stepanov45328242015-05-24 02:47:59 +000060 // 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 Stepanov8e9c70b2015-05-29 22:31:28 +000065 addr = MmapNoAccess(beg, size, name);
Evgeniy Stepanov45328242015-05-24 02:47:59 +000066 }
67 if ((uptr)addr != beg) {
68 uptr end = beg + size - 1;
Viktor Kutuzov30bd3452014-11-28 11:42:55 +000069 Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end);
70 return false;
71 }
72 }
73 return true;
74}
75
Evgeniy Stepanov8441bb22015-01-27 13:20:34 +000076static 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 Stepanov45328242015-05-24 02:47:59 +0000107bool InitShadow(bool init_origins) {
Viktor Kutuzov30bd3452014-11-28 11:42:55 +0000108 // Let user know mapping parameters first.
Sergey Matveev9be70fb2013-12-05 12:04:51 +0000109 VPrintf(1, "__msan_init %p\n", &__msan_init);
Evgeniy Stepanov8441bb22015-01-27 13:20:34 +0000110 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 Stepanovc5033782012-12-11 12:27:27 +0000113
Evgeniy Stepanov8441bb22015-01-27 13:20:34 +0000114 CheckMemoryLayoutSanity();
Viktor Kutuzov30bd3452014-11-28 11:42:55 +0000115
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 Stepanov794a7312012-12-26 06:37:23 +0000119 return false;
120 }
121
Evgeniy Stepanov8441bb22015-01-27 13:20:34 +0000122 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 Stepanov45328242015-05-24 02:47:59 +0000127
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 Stepanov8e9c70b2015-05-29 22:31:28 +0000138 if ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start)
Evgeniy Stepanov45328242015-05-24 02:47:59 +0000139 return false;
Yury Gribov8f848ff2015-02-03 10:15:15 +0000140 if (common_flags()->use_madv_dontdump)
141 DontDumpShadowMemory(start, size);
Evgeniy Stepanov45328242015-05-24 02:47:59 +0000142 }
143 if (protect) {
144 if (!CheckMemoryRangeAvailability(start, size))
145 return false;
Evgeniy Stepanov8e9c70b2015-05-29 22:31:28 +0000146 if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
Evgeniy Stepanov45328242015-05-24 02:47:59 +0000147 return false;
Evgeniy Stepanov8441bb22015-01-27 13:20:34 +0000148 }
Viktor Kutuzov30bd3452014-11-28 11:42:55 +0000149 }
150
Evgeniy Stepanovc5033782012-12-11 12:27:27 +0000151 return true;
152}
153
Evgeniy Stepanov9b52ce92013-01-10 11:17:55 +0000154static void MsanAtExit(void) {
Evgeniy Stepanovad8065f2014-06-24 09:04:06 +0000155 if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
156 ReportStats();
Evgeniy Stepanov9b52ce92013-01-10 11:17:55 +0000157 if (msan_report_count > 0) {
158 ReportAtExitStatistics();
Alexey Samsonovbb79b062015-08-21 20:49:37 +0000159 if (common_flags()->exitcode)
160 internal__exit(common_flags()->exitcode);
Evgeniy Stepanov9b52ce92013-01-10 11:17:55 +0000161 }
162}
163
164void InstallAtExitHandler() {
165 atexit(MsanAtExit);
166}
Reid Klecknerc9d382b2013-03-11 18:07:42 +0000167
Evgeniy Stepanovf653cda2014-04-04 09:47:41 +0000168// ---------------------- TSD ---------------- {{{1
169
170static pthread_key_t tsd_key;
171static bool tsd_key_inited = false;
Evgeniy Stepanov372deb02014-12-17 10:30:06 +0000172
Evgeniy Stepanovf653cda2014-04-04 09:47:41 +0000173void 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 Stepanov372deb02014-12-17 10:30:06 +0000179static THREADLOCAL MsanThread* msan_current_thread;
180
181MsanThread *GetCurrentThread() {
182 return msan_current_thread;
Evgeniy Stepanovf653cda2014-04-04 09:47:41 +0000183}
184
Evgeniy Stepanov372deb02014-12-17 10:30:06 +0000185void 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 Stepanovf653cda2014-04-04 09:47:41 +0000190 CHECK(tsd_key_inited);
Evgeniy Stepanov372deb02014-12-17 10:30:06 +0000191 pthread_setspecific(tsd_key, (void *)t);
Evgeniy Stepanovf653cda2014-04-04 09:47:41 +0000192}
193
194void 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 Stepanov372deb02014-12-17 10:30:06 +0000201 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 Stepanovf653cda2014-04-04 09:47:41 +0000204 MsanThread::TSDDtor(tsd);
205}
206
Vedant Kumar59ba7b82015-10-01 00:22:21 +0000207} // namespace __msan
Evgeniy Stepanovc5033782012-12-11 12:27:27 +0000208
Vedant Kumar59ba7b82015-10-01 00:22:21 +0000209#endif // SANITIZER_FREEBSD || SANITIZER_LINUX