diff options
Diffstat (limited to 'contrib/compiler-rt/lib/msan/msan_linux.cc')
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_linux.cc | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/msan/msan_linux.cc b/contrib/compiler-rt/lib/msan/msan_linux.cc new file mode 100644 index 0000000..0b67b531 --- /dev/null +++ b/contrib/compiler-rt/lib/msan/msan_linux.cc @@ -0,0 +1,188 @@ +//===-- 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 <elf.h> +#include <link.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <unwind.h> +#include <execinfo.h> +#include <sys/time.h> +#include <sys/resource.h> + +#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 |