//===-- msan_linux.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of MemorySanitizer. // // Linux- and FreeBSD-specific code. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "msan.h" #include "msan_thread.h" #include #include #include #include #include #include #include #include #include #include #include #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_procmaps.h" namespace __msan { 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); } } 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; } 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 (!CheckMemoryRangeAvailability(kShadowBeg, kShadowSize) || (init_origins && !CheckMemoryRangeAvailability(kOriginsBeg, kOriginsSize)) || !CheckMemoryRangeAvailability(kBad1Beg, kBad1Size) || !CheckMemoryRangeAvailability(kBad2Beg, kBad2Size) || !CheckMemoryRangeAvailability(kBad3Beg, kBad3Size)) { return false; } if (!ProtectMemoryRange(kBad1Beg, kBad1Size) || !ProtectMemoryRange(kBad2Beg, kBad2Size) || !ProtectMemoryRange(kBad3Beg, kBad3Size)) { return false; } if (map_shadow) { void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowSize); if (shadow != (void*)kShadowBeg) return false; } if (init_origins) { 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); } } 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 // SANITIZER_FREEBSD || SANITIZER_LINUX