//===-- map_test.cpp --------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "tests/scudo_unit_test.h" #include "common.h" #include "mem_map.h" #include #include #if SCUDO_LINUX #include #endif static const char *MappingName = "scudo:test"; TEST(ScudoMapTest, PageSize) { EXPECT_EQ(scudo::getPageSizeCached(), static_cast(sysconf(_SC_PAGESIZE))); } TEST(ScudoMapDeathTest, MapNoAccessUnmap) { const scudo::uptr Size = 4 * scudo::getPageSizeCached(); scudo::ReservedMemoryT ReservedMemory; ASSERT_TRUE(ReservedMemory.create(/*Addr=*/0U, Size, MappingName)); EXPECT_NE(ReservedMemory.getBase(), 0U); EXPECT_DEATH( memset(reinterpret_cast(ReservedMemory.getBase()), 0xaa, Size), ""); ReservedMemory.release(); } TEST(ScudoMapDeathTest, MapUnmap) { const scudo::uptr Size = 4 * scudo::getPageSizeCached(); EXPECT_DEATH( { // Repeat few time to avoid missing crash if it's mmaped by unrelated // code. for (int i = 0; i < 10; ++i) { scudo::MemMapT MemMap; MemMap.map(/*Addr=*/0U, Size, MappingName); scudo::uptr P = MemMap.getBase(); if (P == 0U) continue; MemMap.unmap(); memset(reinterpret_cast(P), 0xbb, Size); } }, ""); } TEST(ScudoMapDeathTest, MapWithGuardUnmap) { const scudo::uptr PageSize = scudo::getPageSizeCached(); const scudo::uptr Size = 4 * PageSize; scudo::ReservedMemoryT ReservedMemory; ASSERT_TRUE( ReservedMemory.create(/*Addr=*/0U, Size + 2 * PageSize, MappingName)); ASSERT_NE(ReservedMemory.getBase(), 0U); scudo::MemMapT MemMap = ReservedMemory.dispatch(ReservedMemory.getBase(), Size + 2 * PageSize); ASSERT_TRUE(MemMap.isAllocated()); scudo::uptr Q = MemMap.getBase() + PageSize; ASSERT_TRUE(MemMap.remap(Q, Size, MappingName)); memset(reinterpret_cast(Q), 0xaa, Size); EXPECT_DEATH(memset(reinterpret_cast(Q), 0xaa, Size + 1), ""); MemMap.unmap(); } TEST(ScudoMapTest, MapGrowUnmap) { const scudo::uptr PageSize = scudo::getPageSizeCached(); const scudo::uptr Size = 4 * PageSize; scudo::ReservedMemoryT ReservedMemory; ReservedMemory.create(/*Addr=*/0U, Size, MappingName); ASSERT_TRUE(ReservedMemory.isCreated()); scudo::MemMapT MemMap = ReservedMemory.dispatch(ReservedMemory.getBase(), Size); ASSERT_TRUE(MemMap.isAllocated()); scudo::uptr Q = MemMap.getBase() + PageSize; ASSERT_TRUE(MemMap.remap(Q, PageSize, MappingName)); memset(reinterpret_cast(Q), 0xaa, PageSize); Q += PageSize; ASSERT_TRUE(MemMap.remap(Q, PageSize, MappingName)); memset(reinterpret_cast(Q), 0xbb, PageSize); MemMap.unmap(); } // Verify that zeroing works properly. TEST(ScudoMapTest, Zeroing) { scudo::ReservedMemoryT ReservedMemory; const scudo::uptr PageSize = scudo::getPageSizeCached(); const scudo::uptr Size = 3 * PageSize; ReservedMemory.create(/*Addr=*/0U, Size, MappingName); ASSERT_TRUE(ReservedMemory.isCreated()); scudo::MemMapT MemMap = ReservedMemory.dispatch(ReservedMemory.getBase(), ReservedMemory.getCapacity()); EXPECT_TRUE( MemMap.remap(MemMap.getBase(), MemMap.getCapacity(), MappingName)); unsigned char *Data = reinterpret_cast(MemMap.getBase()); memset(Data, 1U, MemMap.getCapacity()); // Spot check some values. EXPECT_EQ(1U, Data[0]); EXPECT_EQ(1U, Data[PageSize]); EXPECT_EQ(1U, Data[PageSize * 2]); MemMap.releaseAndZeroPagesToOS(MemMap.getBase(), MemMap.getCapacity()); EXPECT_EQ(0U, Data[0]); EXPECT_EQ(0U, Data[PageSize]); EXPECT_EQ(0U, Data[PageSize * 2]); #if SCUDO_LINUX // Now verify that if madvise fails, the data is still zeroed. memset(Data, 1U, MemMap.getCapacity()); if (mlock(Data, MemMap.getCapacity()) != -1) { EXPECT_EQ(1U, Data[0]); EXPECT_EQ(1U, Data[PageSize]); EXPECT_EQ(1U, Data[PageSize * 2]); MemMap.releaseAndZeroPagesToOS(MemMap.getBase(), MemMap.getCapacity()); EXPECT_EQ(0U, Data[0]); EXPECT_EQ(0U, Data[PageSize]); EXPECT_EQ(0U, Data[PageSize * 2]); EXPECT_NE(-1, munlock(Data, MemMap.getCapacity())); } #endif MemMap.unmap(); }