diff --git a/compiler-rt/lib/scudo/standalone/linux.cpp b/compiler-rt/lib/scudo/standalone/linux.cpp index c2fdf211e22f51..9b5ed67c515d56 100644 --- a/compiler-rt/lib/scudo/standalone/linux.cpp +++ b/compiler-rt/lib/scudo/standalone/linux.cpp @@ -10,6 +10,7 @@ #if SCUDO_LINUX +#include "atomic_helpers.h" #include "common.h" #include "linux.h" #include "mutex.h" @@ -89,9 +90,40 @@ void setMemoryPermission(uptr Addr, uptr Size, uptr Flags, dieOnMapUnmapError(); } +static bool madviseNeedsMemset() { + uptr Size = getPageSizeCached(); + char *P = (char *)mmap(0, Size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (!P) + dieOnMapUnmapError(errno == ENOMEM); + *P = -1; + while (madvise(P, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { + } + bool R = (*P != 0); + if (munmap(P, Size) != 0) + dieOnMapUnmapError(); + return R; +} + +static bool madviseNeedsMemsetCached() { + static atomic_u8 Cache; + enum State : u8 { Unknown = 0, Yes = 1, No = 2 }; + State NeedsMemset = static_cast(atomic_load_relaxed(&Cache)); + if (NeedsMemset == Unknown) { + NeedsMemset = madviseNeedsMemset() ? Yes : No; + atomic_store_relaxed(&Cache, NeedsMemset); + } + return NeedsMemset == Yes; +} + void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, UNUSED MapPlatformData *Data) { void *Addr = reinterpret_cast(BaseAddress + Offset); + if (madviseNeedsMemsetCached()) { + // Workaround for QEMU-user ignoring MADV_DONTNEED. + // https://github.com/qemu/qemu/blob/b1cffefa1b163bce9aebc3416f562c1d3886eeaa/linux-user/syscall.c#L11941 + memset(Addr, 0, Size); + } while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { } }