From 45b6d2c597cbb1a738669fa87e4983f45e6697b0 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 7 Oct 2026 23:17:53 +0400 Subject: [PATCH] memory: copy sparse backing in one traversal --- src/kernel/memoryAddressSpace.inc | 22 ++++++---------------- tests/VirtualMemoryAllocationTests.cpp | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/kernel/memoryAddressSpace.inc b/src/kernel/memoryAddressSpace.inc index 3627366f..47e916f3 100644 --- a/src/kernel/memoryAddressSpace.inc +++ b/src/kernel/memoryAddressSpace.inc @@ -258,28 +258,18 @@ public: g_test_backing_read(vaddr, size); } #endif - const auto end = vaddr + size; - auto first = m_maps.lower_bound(vaddr); - if (first != m_maps.begin()) { - auto previous = std::prev(first); + const auto end = vaddr + size; + auto mapping = m_maps.lower_bound(vaddr); + if (mapping != m_maps.begin()) { + auto previous = std::prev(mapping); if (previous->second.vaddr + previous->second.size > vaddr) { - first = previous; - } - } - for (auto mapping = first; mapping != m_maps.end() && mapping->second.vaddr < end; - ++mapping) { - const auto& entry = mapping->second; - const auto start = std::max(vaddr, entry.vaddr); - const auto bytes = std::min(end, entry.vaddr + entry.size) - start; - if (!RangeOk(entry.backing_offset + start - entry.vaddr, bytes)) { - return false; + mapping = previous; } } auto* destination = static_cast(data); auto cursor = vaddr; - for (auto mapping = first; mapping != m_maps.end() && mapping->second.vaddr < end; - ++mapping) { + for (; mapping != m_maps.end() && mapping->second.vaddr < end; ++mapping) { const auto& entry = mapping->second; const auto start = std::max(vaddr, entry.vaddr); const auto bytes = std::min(end, entry.vaddr + entry.size) - start; diff --git a/tests/VirtualMemoryAllocationTests.cpp b/tests/VirtualMemoryAllocationTests.cpp index 15e1553a..41c0a093 100644 --- a/tests/VirtualMemoryAllocationTests.cpp +++ b/tests/VirtualMemoryAllocationTests.cpp @@ -465,6 +465,24 @@ void TestSparseBackingReadPreservesResidency() { std::all_of(bytes.begin() + commit_size * 2, bytes.end(), [](uint8_t value) { return value == 0xa7; }), "sparse backing read did not copy resident pages and zero nonresident pages"); + constexpr size_t prefix = 37, suffix = 53; + constexpr size_t clipped_size = prefix + commit_size + suffix; + std::fill(bytes.begin(), bytes.end(), 0x5a); + Check(test, + Libs::LibKernel::Memory::TryReadSparseBacking( + base + commit_size - prefix, bytes.data() + 1, clipped_size), + "sparse backing read rejected unaligned resident edges around a hole"); + Check(test, bytes.front() == 0x5a && bytes[clipped_size + 1] == 0x5a, + "clipped sparse backing read overwrote destination canaries"); + Check(test, + std::all_of(bytes.begin() + 1, bytes.begin() + 1 + prefix, + [](uint8_t value) { return value == 0x3c; }) && + std::all_of(bytes.begin() + 1 + prefix, bytes.begin() + 1 + prefix + commit_size, + [](uint8_t value) { return value == 0; }) && + std::all_of(bytes.begin() + 1 + prefix + commit_size, + bytes.begin() + 1 + clipped_size, + [](uint8_t value) { return value == 0xa7; }), + "clipped sparse backing read misplaced resident bytes or the intervening hole"); std::fill(bytes.begin(), bytes.end(), 0x5a); Check(test, Libs::LibKernel::Memory::TryReadSparseBacking(base + commit_size, bytes.data(), bytes.size()),