1 //===-- msan_linux.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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
18 #include "msan_report.h"
19 #include "msan_thread.h"
30 #include <sys/resource.h>
32 #include "sanitizer_common/sanitizer_common.h"
33 #include "sanitizer_common/sanitizer_procmaps.h"
37 void ReportMapRange(const char *descr
, uptr beg
, uptr size
) {
39 uptr end
= beg
+ size
- 1;
40 VPrintf(1, "%s : %p - %p\n", descr
, beg
, end
);
44 static bool CheckMemoryRangeAvailability(uptr beg
, uptr size
) {
46 uptr end
= beg
+ size
- 1;
47 if (!MemoryRangeIsAvailable(beg
, end
)) {
48 Printf("FATAL: Memory range %p - %p is not available.\n", beg
, end
);
55 static bool ProtectMemoryRange(uptr beg
, uptr size
, const char *name
) {
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();
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
,
76 static void CheckMemoryLayoutSanity() {
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
;
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
) {
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
)));
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
)));
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",
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
)
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
);
142 if (!CheckMemoryRangeAvailability(start
, size
))
144 if (!MmapFixedSuperNoReserve(start
, size
, kMemoryLayout
[i
].name
))
146 if (common_flags()->use_madv_dontdump
)
147 DontDumpShadowMemory(start
, size
);
150 if (!CheckMemoryRangeAvailability(start
, size
))
152 if (!ProtectMemoryRange(start
, size
, kMemoryLayout
[i
].name
))
160 static void MsanAtExit(void) {
161 if (flags()->print_stats
&& (flags()->atexit
|| msan_report_count
> 0))
163 if (msan_report_count
> 0) {
164 ReportAtExitStatistics();
165 if (common_flags()->exitcode
)
166 internal__exit(common_flags()->exitcode
);
170 void InstallAtExitHandler() {
174 // ---------------------- TSD ---------------- {{{1
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;
184 tsd_key() : key(nullptr) {}
186 CHECK(tsd_destructor
);
188 (*tsd_destructor
)(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
);
205 void SetCurrentThread(MsanThread
*tsd
) {
206 CHECK(tsd_destructor
);
212 void MsanTSDDtor(void *tsd
) {
213 CHECK(tsd_destructor
);
214 CHECK_EQ(key
.key
, tsd
);
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
);
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
));
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
);
259 } // namespace __msan
261 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD