diff --git a/compiler-rt/lib/asan/asan_poisoning.h b/compiler-rt/lib/asan/asan_poisoning.h --- a/compiler-rt/lib/asan/asan_poisoning.h +++ b/compiler-rt/lib/asan/asan_poisoning.h @@ -15,6 +15,7 @@ #include "asan_internal.h" #include "asan_mapping.h" #include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform.h" namespace __asan { @@ -67,7 +68,15 @@ if (page_end != shadow_end) { REAL(memset)((void *)page_end, 0, shadow_end - page_end); } - ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); +# ifdef SANITIZER_LINUX + // MADV_DONTNEED is not guaranteed to succeed. In particular it fails + // on locked pages. We never lock any shadow pages ourselves, but let's + // not assume that the user would never attempt to lock the entire process + // (e.g. using mlockall). However, if it does succeed, we are guaranteed + // that future accesses will be zero'd. + if (ReleaseMemoryPagesToOSAndZeroFill(page_beg, page_end) != 0) +# endif + ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); } } #endif // SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -126,13 +126,8 @@ // Releases memory pages entirely within the [beg, end] address range. // The pages no longer count toward RSS; reads are guaranteed to return 0. // Requires (but does not verify!) that pages are MAP_PRIVATE. -inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { - // man madvise on Linux promises zero-fill for anonymous private pages. - // Testing shows the same behaviour for private (but not anonymous) mappings - // of shm_open() files, as long as the underlying file is untouched. - CHECK(SANITIZER_LINUX); - ReleaseMemoryPagesToOS(beg, end); -} +// Returns 0 on success, -1 on error. +int ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end); #if SANITIZER_ANDROID diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -2374,6 +2374,22 @@ return true; } +int ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { + // man madvise on Linux promises zero-fill for anonymous private pages. + // Testing shows the same behaviour for private (but not anonymous) mappings + // of shm_open() files, as long as the underlying file is untouched. + CHECK(SANITIZER_LINUX); + // This is the same as ReleaseMemoryPagesToOS, but with additional error + // handling. + uptr page_size = GetPageSizeCached(); + uptr beg_aligned = RoundUpTo(beg, page_size); + uptr end_aligned = RoundDownTo(end, page_size); + if (beg_aligned < end_aligned) + return internal_madvise(beg_aligned, end_aligned - beg_aligned, + SANITIZER_MADVISE_DONTNEED); + return 0; +} + } // namespace __sanitizer #endif