Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler-rt/lib/scudo/standalone/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ u32 getThreadID();
constexpr uptr MaxRandomLength = 256U;
bool getRandom(void *Buffer, uptr Length, bool Blocking = false);

// Get the total number of resident pages for BaseAddress to BaseAddress + Size.
// This function can run slowly, and is only expected to be called
// from getStats functions where performance does not matter.
u64 getResidentPages(uptr BaseAddress, uptr Size);

// Platform memory mapping functions.

#define MAP_ALLOWNOMEM (1U << 0)
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/scudo/standalone/fuchsia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ void outputRaw(const char *Buffer) {

void setAbortMessage(const char *Message) {}

u64 getResidentPages(uptr BaseAddress, uptr Size) { return 0; }

} // namespace scudo

#endif // SCUDO_FUCHSIA
28 changes: 28 additions & 0 deletions compiler-rt/lib/scudo/standalone/linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,34 @@ void setAbortMessage(const char *Message) {
android_set_abort_message(Message);
}

u64 getResidentPages(uptr BaseAddress, uptr Size) {
unsigned char PageData[256];

uptr PageSize = getPageSizeCached();
uptr PageSizeLog = getPageSizeLogCached();

// Make sure the address is page aligned.
uptr CurrentAddress = BaseAddress & ~(PageSize - 1);
uptr LastAddress = roundUp(BaseAddress + Size, PageSize);
u64 ResidentPages = 0;
while (CurrentAddress < LastAddress) {
uptr Length = LastAddress - CurrentAddress;
if ((Length >> PageSizeLog) > sizeof(PageData)) {
Length = sizeof(PageData) << PageSizeLog;
}
if (mincore(reinterpret_cast<void *>(CurrentAddress), Length, PageData) ==
-1)
break;
for (size_t I = 0; I < Length >> PageSizeLog; I++) {
if (PageData[I])
ResidentPages++;
}
CurrentAddress += Length;
}

return ResidentPages;
}

} // namespace scudo

#endif // SCUDO_LINUX
18 changes: 16 additions & 2 deletions compiler-rt/lib/scudo/standalone/secondary.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#ifndef SCUDO_SECONDARY_H_
#define SCUDO_SECONDARY_H_

#ifndef __STDC_FORMAT_MACROS
// Ensure PRId64 macro is available
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>

#include "chunk.h"
#include "common.h"
#include "list.h"
Expand Down Expand Up @@ -221,9 +227,17 @@ class MapAllocatorCache {

for (CachedBlock &Entry : LRUEntries) {
Str->append(" StartBlockAddress: 0x%zx, EndBlockAddress: 0x%zx, "
"BlockSize: %zu %s\n",
"BlockSize: %zu%s",
Entry.CommitBase, Entry.CommitBase + Entry.CommitSize,
Entry.CommitSize, Entry.Time == 0 ? "[R]" : "");
Entry.CommitSize, Entry.Time == 0 ? " [R]" : "");
#if SCUDO_LINUX
// getResidentPages only works on linux systems currently.
Str->append(", Resident Pages: %" PRId64 "/%zu\n",
getResidentPages(Entry.CommitBase, Entry.CommitSize),
Entry.CommitSize / getPageSizeCached());
#else
Str->append("\n");
#endif
}
}

Expand Down
78 changes: 51 additions & 27 deletions compiler-rt/lib/scudo/standalone/tests/common_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,74 @@

namespace scudo {

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;
}
}
TEST(ScudoCommonTest, VerifyGetResidentPages) {
if (!SCUDO_LINUX)
GTEST_SKIP() << "Only valid on linux systems.";

constexpr uptr NumPages = 512;
const uptr SizeBytes = NumPages * getPageSizeCached();

MemMapT MemMap;
ASSERT_TRUE(MemMap.map(/*Addr=*/0U, SizeBytes, "ResidentMemorySize"));
ASSERT_NE(MemMap.getBase(), 0U);

// Only android seem to properly detect when single pages are touched.
#if SCUDO_ANDROID
// Verify nothing should be mapped in right after the map is created.
EXPECT_EQ(0U, getResidentPages(MemMap.getBase(), SizeBytes));

// Touch a page.
u8 *Data = reinterpret_cast<u8 *>(MemMap.getBase());
Data[0] = 1;
EXPECT_EQ(1U, getResidentPages(MemMap.getBase(), SizeBytes));

// Touch a non-consective page.
Data[getPageSizeCached() * 2] = 1;
EXPECT_EQ(2U, getResidentPages(MemMap.getBase(), SizeBytes));

// Touch a page far enough that the function has to make multiple calls
// to mincore.
Data[getPageSizeCached() * 300] = 1;
EXPECT_EQ(3U, getResidentPages(MemMap.getBase(), SizeBytes));

// Touch another page in the same range to make sure the second
// read is working.
Data[getPageSizeCached() * 400] = 1;
EXPECT_EQ(4U, getResidentPages(MemMap.getBase(), SizeBytes));
#endif

// Now write the whole thing.
memset(reinterpret_cast<void *>(MemMap.getBase()), 1, SizeBytes);
EXPECT_EQ(NumPages, getResidentPages(MemMap.getBase(), SizeBytes));

MemMap.unmap();
}

// Fuchsia needs getResidentPages implementation.
TEST(ScudoCommonTest, SKIP_ON_FUCHSIA(ResidentMemorySize)) {
// 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;
TEST(ScudoCommonTest, VerifyReleasePagesToOS) {
if (!SCUDO_LINUX)
GTEST_SKIP() << "Only valid on linux systems.";

constexpr uptr NumPages = 1000;
const uptr SizeBytes = NumPages * getPageSizeCached();

MemMapT MemMap;
ASSERT_TRUE(MemMap.map(/*Addr=*/0U, SizeBytes, "ResidentMemorySize"));
ASSERT_NE(MemMap.getBase(), 0U);

void *P = reinterpret_cast<void *>(MemMap.getBase());
size_t ResidentPages;
getResidentPages(P, NumPages, &ResidentPages);
EXPECT_EQ(0U, ResidentPages);
EXPECT_EQ(0U, getResidentPages(MemMap.getBase(), SizeBytes));

// Make the entire map resident.
memset(P, 1, SizeBytes);
getResidentPages(P, NumPages, &ResidentPages);
EXPECT_EQ(NumPages, ResidentPages);
EXPECT_EQ(NumPages, getResidentPages(MemMap.getBase(), SizeBytes));

// Should release the memory to the kernel immediately.
MemMap.releasePagesToOS(MemMap.getBase(), SizeBytes);
getResidentPages(P, NumPages, &ResidentPages);
EXPECT_EQ(0U, ResidentPages);
EXPECT_EQ(0U, getResidentPages(MemMap.getBase(), SizeBytes));

// Make the entire map resident again.
memset(P, 1, SizeBytes);
getResidentPages(P, NumPages, &ResidentPages);
EXPECT_EQ(NumPages, ResidentPages);
EXPECT_EQ(NumPages, getResidentPages(MemMap.getBase(), SizeBytes));

MemMap.unmap();
}
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/scudo/standalone/trusty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ void outputRaw(const char *Buffer) { printf("%s", Buffer); }

void setAbortMessage(UNUSED const char *Message) {}

u64 getResidentPages(UNUSED uptr BaseAddress, UNUSED uptr Size) { return 0; }

} // namespace scudo

#endif // SCUDO_TRUSTY
Loading