[scudo] Check if MADV_DONTNEED zeroes memory am: 2291410e54 am: 7828a5f1a8 am: f4abe420a0
Original change: https://android-review.googlesource.com/c/platform/external/scudo/+/1683518
Change-Id: I53b960a1a1f60797065f5ab8258f20d9c6a1d584
diff --git a/standalone/linux.cpp b/standalone/linux.cpp
index c2fdf21..9b5ed67 100644
--- a/standalone/linux.cpp
+++ b/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 @@
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<State>(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<void *>(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) {
}
}