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 @@ -10,6 +10,7 @@ #if SCUDO_LINUX +#include "atomic_helpers.h" #include "common.h" #include "linux.h" #include "mutex.h" @@ -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 Cache; + u8 NeedsMemset = atomic_load_relaxed(&Cache); + if (!NeedsMemset) { + NeedsMemset = madviseNeedsMemset() ? 1 : 2; + atomic_store_relaxed(&Cache, NeedsMemset); + } + return NeedsMemset == 1; +} + 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. + memset(Addr, 0, Size); + } while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { } }