[DominatorTree] Add support for mixed pre/post CFG views.
[llvm-project.git] / compiler-rt / lib / msan / msan_linux.cpp
blobd5baee38e710237ed792623b0fe694ce87604e08
1 //===-- msan_linux.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of MemorySanitizer.
11 // Linux-, NetBSD- and FreeBSD-specific code.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_platform.h"
15 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
17 #include "msan.h"
18 #include "msan_report.h"
19 #include "msan_thread.h"
21 #include <elf.h>
22 #include <link.h>
23 #include <pthread.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <unwind.h>
29 #include <sys/time.h>
30 #include <sys/resource.h>
32 #include "sanitizer_common/sanitizer_common.h"
33 #include "sanitizer_common/sanitizer_procmaps.h"
35 namespace __msan {
37 void ReportMapRange(const char *descr, uptr beg, uptr size) {
38 if (size > 0) {
39 uptr end = beg + size - 1;
40 VPrintf(1, "%s : %p - %p\n", descr, beg, end);
44 static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
45 if (size > 0) {
46 uptr end = beg + size - 1;
47 if (!MemoryRangeIsAvailable(beg, end)) {
48 Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
49 return false;
52 return true;
55 static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
56 if (size > 0) {
57 void *addr = MmapFixedNoAccess(beg, size, name);
58 if (beg == 0 && addr) {
59 // Depending on the kernel configuration, we may not be able to protect
60 // the page at address zero.
61 uptr gap = 16 * GetPageSizeCached();
62 beg += gap;
63 size -= gap;
64 addr = MmapFixedNoAccess(beg, size, name);
66 if ((uptr)addr != beg) {
67 uptr end = beg + size - 1;
68 Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end,
69 name);
70 return false;
73 return true;
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)));
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)));
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)));
103 prev_end = end;
107 bool InitShadow(bool init_origins) {
108 // Let user know mapping parameters first.
109 VPrintf(1, "__msan_init %p\n", &__msan_init);
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);
114 CheckMemoryLayoutSanity();
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);
119 return false;
122 const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
124 for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
125 uptr start = kMemoryLayout[i].start;
126 uptr end = kMemoryLayout[i].end;
127 uptr size = end - start;
128 MappingDesc::Type type = kMemoryLayout[i].type;
130 // Check if the segment should be mapped based on platform constraints.
131 if (start >= maxVirtualAddress)
132 continue;
134 bool map = type == MappingDesc::SHADOW ||
135 (init_origins && type == MappingDesc::ORIGIN);
136 bool protect = type == MappingDesc::INVALID ||
137 (!init_origins && type == MappingDesc::ORIGIN);
138 CHECK(!(map && protect));
139 if (!map && !protect)
140 CHECK(type == MappingDesc::APP);
141 if (map) {
142 if (!CheckMemoryRangeAvailability(start, size))
143 return false;
144 if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
145 return false;
146 if (common_flags()->use_madv_dontdump)
147 DontDumpShadowMemory(start, size);
149 if (protect) {
150 if (!CheckMemoryRangeAvailability(start, size))
151 return false;
152 if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
153 return false;
157 return true;
160 static void MsanAtExit(void) {
161 if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
162 ReportStats();
163 if (msan_report_count > 0) {
164 ReportAtExitStatistics();
165 if (common_flags()->exitcode)
166 internal__exit(common_flags()->exitcode);
170 void InstallAtExitHandler() {
171 atexit(MsanAtExit);
174 // ---------------------- TSD ---------------- {{{1
176 #if SANITIZER_NETBSD
177 // Thread Static Data cannot be used in early init on NetBSD.
178 // Reuse the MSan TSD API for compatibility with existing code
179 // with an alternative implementation.
181 static void (*tsd_destructor)(void *tsd) = nullptr;
183 struct tsd_key {
184 tsd_key() : key(nullptr) {}
185 ~tsd_key() {
186 CHECK(tsd_destructor);
187 if (key)
188 (*tsd_destructor)(key);
190 MsanThread *key;
193 static thread_local struct tsd_key key;
195 void MsanTSDInit(void (*destructor)(void *tsd)) {
196 CHECK(!tsd_destructor);
197 tsd_destructor = destructor;
200 MsanThread *GetCurrentThread() {
201 CHECK(tsd_destructor);
202 return key.key;
205 void SetCurrentThread(MsanThread *tsd) {
206 CHECK(tsd_destructor);
207 CHECK(tsd);
208 CHECK(!key.key);
209 key.key = tsd;
212 void MsanTSDDtor(void *tsd) {
213 CHECK(tsd_destructor);
214 CHECK_EQ(key.key, tsd);
215 key.key = nullptr;
216 // Make sure that signal handler can not see a stale current thread pointer.
217 atomic_signal_fence(memory_order_seq_cst);
218 MsanThread::TSDDtor(tsd);
220 #else
221 static pthread_key_t tsd_key;
222 static bool tsd_key_inited = false;
224 void MsanTSDInit(void (*destructor)(void *tsd)) {
225 CHECK(!tsd_key_inited);
226 tsd_key_inited = true;
227 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
230 static THREADLOCAL MsanThread* msan_current_thread;
232 MsanThread *GetCurrentThread() {
233 return msan_current_thread;
236 void SetCurrentThread(MsanThread *t) {
237 // Make sure we do not reset the current MsanThread.
238 CHECK_EQ(0, msan_current_thread);
239 msan_current_thread = t;
240 // Make sure that MsanTSDDtor gets called at the end.
241 CHECK(tsd_key_inited);
242 pthread_setspecific(tsd_key, (void *)t);
245 void MsanTSDDtor(void *tsd) {
246 MsanThread *t = (MsanThread*)tsd;
247 if (t->destructor_iterations_ > 1) {
248 t->destructor_iterations_--;
249 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
250 return;
252 msan_current_thread = nullptr;
253 // Make sure that signal handler can not see a stale current thread pointer.
254 atomic_signal_fence(memory_order_seq_cst);
255 MsanThread::TSDDtor(tsd);
257 #endif
259 } // namespace __msan
261 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD