Skip to content

Commit 3e28992

Browse files
authored
[scudo] Always zero on linux even if the memory cannot be released. (#167788)
If a caller has locked memory, then the madvise call will fail. In that case, zero the memory so that we don't return non-zeroed memory for calloc calls since we thought the memory had been released.
1 parent e51163c commit 3e28992

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

compiler-rt/lib/scudo/standalone/mem_map_linux.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,12 @@ void MemMapLinux::setMemoryPermissionImpl(uptr Addr, uptr Size, uptr Flags) {
122122
void MemMapLinux::releaseAndZeroPagesToOSImpl(uptr From, uptr Size) {
123123
void *Addr = reinterpret_cast<void *>(From);
124124

125-
while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) {
125+
int rc;
126+
while ((rc = madvise(Addr, Size, MADV_DONTNEED)) == -1 && errno == EAGAIN) {
127+
}
128+
if (rc == -1) {
129+
// If we can't madvies the memory, then we still need to zero it.
130+
memset(Addr, 0, Size);
126131
}
127132
}
128133

compiler-rt/lib/scudo/standalone/tests/map_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#include <string.h>
1515
#include <unistd.h>
1616

17+
#if SCUDO_LINUX
18+
#include <sys/mman.h>
19+
#endif
20+
1721
static const char *MappingName = "scudo:test";
1822

1923
TEST(ScudoMapTest, PageSize) {
@@ -89,3 +93,45 @@ TEST(ScudoMapTest, MapGrowUnmap) {
8993
memset(reinterpret_cast<void *>(Q), 0xbb, PageSize);
9094
MemMap.unmap();
9195
}
96+
97+
// Verify that zeroing works properly.
98+
TEST(ScudoMapTest, Zeroing) {
99+
scudo::ReservedMemoryT ReservedMemory;
100+
const scudo::uptr PageSize = scudo::getPageSizeCached();
101+
const scudo::uptr Size = 3 * PageSize;
102+
ReservedMemory.create(/*Addr=*/0U, Size, MappingName);
103+
ASSERT_TRUE(ReservedMemory.isCreated());
104+
105+
scudo::MemMapT MemMap = ReservedMemory.dispatch(ReservedMemory.getBase(),
106+
ReservedMemory.getCapacity());
107+
EXPECT_TRUE(
108+
MemMap.remap(MemMap.getBase(), MemMap.getCapacity(), MappingName));
109+
unsigned char *Data = reinterpret_cast<unsigned char *>(MemMap.getBase());
110+
memset(Data, 1U, MemMap.getCapacity());
111+
// Spot check some values.
112+
EXPECT_EQ(1U, Data[0]);
113+
EXPECT_EQ(1U, Data[PageSize]);
114+
EXPECT_EQ(1U, Data[PageSize * 2]);
115+
MemMap.releaseAndZeroPagesToOS(MemMap.getBase(), MemMap.getCapacity());
116+
EXPECT_EQ(0U, Data[0]);
117+
EXPECT_EQ(0U, Data[PageSize]);
118+
EXPECT_EQ(0U, Data[PageSize * 2]);
119+
120+
#if SCUDO_LINUX
121+
// Now verify that if madvise fails, the data is still zeroed.
122+
memset(Data, 1U, MemMap.getCapacity());
123+
EXPECT_NE(-1, mlock(Data, MemMap.getCapacity()));
124+
125+
EXPECT_EQ(1U, Data[0]);
126+
EXPECT_EQ(1U, Data[PageSize]);
127+
EXPECT_EQ(1U, Data[PageSize * 2]);
128+
MemMap.releaseAndZeroPagesToOS(MemMap.getBase(), MemMap.getCapacity());
129+
EXPECT_EQ(0U, Data[0]);
130+
EXPECT_EQ(0U, Data[PageSize]);
131+
EXPECT_EQ(0U, Data[PageSize * 2]);
132+
133+
EXPECT_NE(-1, munlock(Data, MemMap.getCapacity()));
134+
#endif
135+
136+
MemMap.unmap();
137+
}

0 commit comments

Comments
 (0)