[scudo] Make release to OS test more specific. (#147852)
The original version of ResidentMemorySize could be a little flaky.
Replace the test with a version that verifies exactly how much of the
map is resident.
GitOrigin-RevId: 34b3ea367c4299ebd7c37edc7c748c9627ee66cb
diff --git a/lib/scudo/standalone/tests/common_test.cpp b/lib/scudo/standalone/tests/common_test.cpp
index e6ddbb0..71f810e 100644
--- a/lib/scudo/standalone/tests/common_test.cpp
+++ b/lib/scudo/standalone/tests/common_test.cpp
@@ -11,44 +11,60 @@
#include "common.h"
#include "mem_map.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+
#include <algorithm>
-#include <fstream>
+#include <vector>
namespace scudo {
-static uptr getResidentMemorySize() {
- if (!SCUDO_LINUX)
- UNREACHABLE("Not implemented!");
- uptr Size;
- uptr Resident;
- std::ifstream IFS("/proc/self/statm");
- IFS >> Size;
- IFS >> Resident;
- return Resident * getPageSizeCached();
+static void getResidentPages(void *BaseAddress, size_t TotalPages,
+ size_t *ResidentPages) {
+ std::vector<unsigned char> Pages(TotalPages, 0);
+ ASSERT_EQ(
+ 0, mincore(BaseAddress, TotalPages * getPageSizeCached(), Pages.data()))
+ << strerror(errno);
+ *ResidentPages = 0;
+ for (unsigned char Value : Pages) {
+ if (Value & 1) {
+ ++*ResidentPages;
+ }
+ }
}
-// Fuchsia needs getResidentMemorySize implementation.
+// Fuchsia needs getResidentPages implementation.
TEST(ScudoCommonTest, SKIP_ON_FUCHSIA(ResidentMemorySize)) {
- uptr OnStart = getResidentMemorySize();
- EXPECT_GT(OnStart, 0UL);
-
- const uptr Size = 1ull << 30;
- const uptr Threshold = Size >> 3;
+ // Make sure to have the size of the map on a page boundary.
+ const uptr PageSize = getPageSizeCached();
+ const size_t NumPages = 1000;
+ const uptr SizeBytes = NumPages * PageSize;
MemMapT MemMap;
- ASSERT_TRUE(MemMap.map(/*Addr=*/0U, Size, "ResidentMemorySize"));
+ ASSERT_TRUE(MemMap.map(/*Addr=*/0U, SizeBytes, "ResidentMemorySize"));
ASSERT_NE(MemMap.getBase(), 0U);
+
void *P = reinterpret_cast<void *>(MemMap.getBase());
- EXPECT_LT(getResidentMemorySize(), OnStart + Threshold);
+ size_t ResidentPages;
+ getResidentPages(P, NumPages, &ResidentPages);
+ EXPECT_EQ(0U, ResidentPages);
- memset(P, 1, Size);
- EXPECT_GT(getResidentMemorySize(), OnStart + Size - Threshold);
+ // Make the entire map resident.
+ memset(P, 1, SizeBytes);
+ getResidentPages(P, NumPages, &ResidentPages);
+ EXPECT_EQ(NumPages, ResidentPages);
- MemMap.releasePagesToOS(MemMap.getBase(), Size);
- EXPECT_LT(getResidentMemorySize(), OnStart + Threshold);
+ // Should release the memory to the kernel immediately.
+ MemMap.releasePagesToOS(MemMap.getBase(), SizeBytes);
+ getResidentPages(P, NumPages, &ResidentPages);
+ EXPECT_EQ(0U, ResidentPages);
- memset(P, 1, Size);
- EXPECT_GT(getResidentMemorySize(), OnStart + Size - Threshold);
+ // Make the entire map resident again.
+ memset(P, 1, SizeBytes);
+ getResidentPages(P, NumPages, &ResidentPages);
+ EXPECT_EQ(NumPages, ResidentPages);
MemMap.unmap();
}