diff --git a/compiler-rt/lib/scudo/standalone/linux.cpp b/compiler-rt/lib/scudo/standalone/linux.cpp --- a/compiler-rt/lib/scudo/standalone/linux.cpp +++ b/compiler-rt/lib/scudo/standalone/linux.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "atomic_helpers.h" #include "platform.h" #if SCUDO_LINUX @@ -89,9 +90,38 @@ dieOnMapUnmapError(); } +static bool madviseNeedsMemset() { + uptr Size = getPageSize(); + 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 NeedsMemset; + u8 Z = atomic_load_relaxed(&NeedsMemset); + if (!Z) { + Z = madviseNeedsMemset() ? 1 : 2; + atomic_store_relaxed(&NeedsMemset, Z); + } + return Z == 1; +} + void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, UNUSED MapPlatformData *Data) { void *Addr = reinterpret_cast(BaseAddress + Offset); + if (madviseNeedsMemsetCached()) { + // Workaround for QEMU-user which ignores MADV_DONTNEED. + memset(Addr, 0, Size); + } while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { } }