diff options
Diffstat (limited to 'lib/msan/msan_linux.cc')
-rw-r--r-- | lib/msan/msan_linux.cc | 156 |
1 files changed, 121 insertions, 35 deletions
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc index 46f501e488c52..0b67b531d51ca 100644 --- a/lib/msan/msan_linux.cc +++ b/lib/msan/msan_linux.cc @@ -9,16 +9,18 @@ // // This file is a part of MemorySanitizer. // -// Linux-specific code. +// Linux- and FreeBSD-specific code. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX #include "msan.h" +#include "msan_thread.h" #include <elf.h> #include <link.h> +#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> @@ -33,63 +35,117 @@ namespace __msan { -static const uptr kMemBeg = 0x600000000000; -static const uptr kMemEnd = 0x7fffffffffff; -static const uptr kShadowBeg = MEM_TO_SHADOW(kMemBeg); -static const uptr kShadowEnd = MEM_TO_SHADOW(kMemEnd); -static const uptr kBad1Beg = 0x100000000; // 4G -static const uptr kBad1End = kShadowBeg - 1; -static const uptr kBad2Beg = kShadowEnd + 1; -static const uptr kBad2End = kMemBeg - 1; -static const uptr kOriginsBeg = kBad2Beg; -static const uptr kOriginsEnd = kBad2End; - -bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins) { - if ((uptr) & InitShadow < kMemBeg) { - Printf("FATAL: Code below application range: %p < %p. Non-PIE build?\n", - &InitShadow, (void *)kMemBeg); - return false; +void ReportMapRange(const char *descr, uptr beg, uptr size) { + if (size > 0) { + uptr end = beg + size - 1; + VPrintf(1, "%s : %p - %p\n", descr, beg, end); } +} - if (common_flags()->verbosity) { - Printf("__msan_init %p\n", &__msan_init); - Printf("Memory : %p %p\n", kMemBeg, kMemEnd); - Printf("Bad2 : %p %p\n", kBad2Beg, kBad2End); - Printf("Origins : %p %p\n", kOriginsBeg, kOriginsEnd); - Printf("Shadow : %p %p\n", kShadowBeg, kShadowEnd); - Printf("Bad1 : %p %p\n", kBad1Beg, kBad1End); +static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { + if (size > 0) { + uptr end = beg + size - 1; + if (!MemoryRangeIsAvailable(beg, end)) { + Printf("FATAL: Memory range %p - %p is not available.\n", beg, end); + return false; + } } + return true; +} - if (!MemoryRangeIsAvailable(kShadowBeg, - init_origins ? kOriginsEnd : kShadowEnd)) { - Printf("FATAL: Shadow memory range is not available.\n"); +static bool ProtectMemoryRange(uptr beg, uptr size) { + if (size > 0) { + uptr end = beg + size - 1; + if (!Mprotect(beg, size)) { + Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end); + return false; + } + } + return true; +} + +bool InitShadow(bool map_shadow, bool init_origins) { + // Let user know mapping parameters first. + VPrintf(1, "__msan_init %p\n", &__msan_init); + ReportMapRange("Low Memory ", kLowMemBeg, kLowMemSize); + ReportMapRange("Bad1 ", kBad1Beg, kBad1Size); + ReportMapRange("Shadow ", kShadowBeg, kShadowSize); + ReportMapRange("Bad2 ", kBad2Beg, kBad2Size); + ReportMapRange("Origins ", kOriginsBeg, kOriginsSize); + ReportMapRange("Bad3 ", kBad3Beg, kBad3Size); + ReportMapRange("High Memory", kHighMemBeg, kHighMemSize); + + // Check mapping sanity (the invariant). + CHECK_EQ(kLowMemBeg, 0); + CHECK_EQ(kBad1Beg, kLowMemBeg + kLowMemSize); + CHECK_EQ(kShadowBeg, kBad1Beg + kBad1Size); + CHECK_GT(kShadowSize, 0); + CHECK_GE(kShadowSize, kLowMemSize + kHighMemSize); + CHECK_EQ(kBad2Beg, kShadowBeg + kShadowSize); + CHECK_EQ(kOriginsBeg, kBad2Beg + kBad2Size); + CHECK_EQ(kOriginsSize, kShadowSize); + CHECK_EQ(kBad3Beg, kOriginsBeg + kOriginsSize); + CHECK_EQ(kHighMemBeg, kBad3Beg + kBad3Size); + CHECK_GT(kHighMemSize, 0); + CHECK_GE(kHighMemBeg + kHighMemSize, kHighMemBeg); // Tests for no overflow. + + if (kLowMemSize > 0) { + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kLowMemBeg))); + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kLowMemBeg + kLowMemSize - 1))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kLowMemBeg))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kLowMemBeg + kLowMemSize - 1))); + } + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kHighMemBeg))); + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kHighMemBeg + kHighMemSize - 1))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kHighMemBeg))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kHighMemBeg + kHighMemSize - 1))); + + if (!MEM_IS_APP(&__msan_init)) { + Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", + (uptr)&__msan_init); return false; } - if (prot1 && !Mprotect(kBad1Beg, kBad1End - kBad1Beg)) + if (!CheckMemoryRangeAvailability(kShadowBeg, kShadowSize) || + (init_origins && + !CheckMemoryRangeAvailability(kOriginsBeg, kOriginsSize)) || + !CheckMemoryRangeAvailability(kBad1Beg, kBad1Size) || + !CheckMemoryRangeAvailability(kBad2Beg, kBad2Size) || + !CheckMemoryRangeAvailability(kBad3Beg, kBad3Size)) { return false; - if (prot2 && !Mprotect(kBad2Beg, kBad2End - kBad2Beg)) + } + + if (!ProtectMemoryRange(kBad1Beg, kBad1Size) || + !ProtectMemoryRange(kBad2Beg, kBad2Size) || + !ProtectMemoryRange(kBad3Beg, kBad3Size)) { return false; + } + if (map_shadow) { - void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg); + void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowSize); if (shadow != (void*)kShadowBeg) return false; } if (init_origins) { - void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsEnd - kOriginsBeg); + void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsSize); if (origins != (void*)kOriginsBeg) return false; } return true; } void MsanDie() { + if (common_flags()->coverage) + __sanitizer_cov_dump(); + if (death_callback) + death_callback(); _exit(flags()->exit_code); } static void MsanAtExit(void) { + if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) + ReportStats(); if (msan_report_count > 0) { ReportAtExitStatistics(); - if (flags()->exit_code) - _exit(flags()->exit_code); + if (flags()->exit_code) _exit(flags()->exit_code); } } @@ -97,6 +153,36 @@ void InstallAtExitHandler() { atexit(MsanAtExit); } +// ---------------------- TSD ---------------- {{{1 + +static pthread_key_t tsd_key; +static bool tsd_key_inited = false; +void MsanTSDInit(void (*destructor)(void *tsd)) { + CHECK(!tsd_key_inited); + tsd_key_inited = true; + CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); +} + +void *MsanTSDGet() { + CHECK(tsd_key_inited); + return pthread_getspecific(tsd_key); +} + +void MsanTSDSet(void *tsd) { + CHECK(tsd_key_inited); + pthread_setspecific(tsd_key, tsd); +} + +void MsanTSDDtor(void *tsd) { + MsanThread *t = (MsanThread*)tsd; + if (t->destructor_iterations_ > 1) { + t->destructor_iterations_--; + CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); + return; + } + MsanThread::TSDDtor(tsd); +} + } // namespace __msan -#endif // __linux__ +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX |