From 00c35c159cf456a299e9c005ff6ac57b27092081 Mon Sep 17 00:00:00 2001 From: David-cmrg <202826622+David-cmrg@users.noreply.github.com> Date: Tue, 13 Oct 2026 03:38:29 +0200 Subject: [PATCH] fix(libc): keep a moved mspace block's usable bytes in realloc --- core/libs/prx/libc/src/Mspace.cpp | 24 ++++++++---------------- core/libs/tests/Mspace.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/core/libs/prx/libc/src/Mspace.cpp b/core/libs/prx/libc/src/Mspace.cpp index 67ad5f794..be9746f2b 100644 --- a/core/libs/prx/libc/src/Mspace.cpp +++ b/core/libs/prx/libc/src/Mspace.cpp @@ -22,7 +22,6 @@ constexpr std::uintptr_t ArenaHeaderBytes = 64; struct Chunk { std::uintptr_t end; bool used; - std::size_t requested; }; struct Arena { @@ -51,7 +50,7 @@ Arena* Find(void* handle) { } void AddFree(Arena& arena, std::uintptr_t start, std::uintptr_t end) { - arena.chunks[start] = {end, false, 0}; + arena.chunks[start] = {end, false}; arena.free.emplace(end - start, start); } @@ -78,7 +77,7 @@ void* Allocate(Arena* arena, std::size_t size, std::size_t alignment) { if (aligned > start) AddFree(*arena, start, aligned); const auto finish = aligned + needed; if (finish < end) AddFree(*arena, finish, end); - arena->chunks[aligned] = {finish, true, size}; + arena->chunks[aligned] = {finish, true}; arena->inUse += needed; arena->peakInUse = std::max(arena->peakInUse, arena->inUse); return reinterpret_cast(aligned); @@ -220,10 +219,7 @@ void* APS5_VABI sceLibcMspaceRealloc_nid_postfix(void* handle, void* pointer, st if (needed < size) { Error(12); return nullptr; } const auto start = chunk->first; const auto capacity = chunk->second.end - start; - if (needed <= capacity) { - chunk->second.requested = size; - return pointer; - } + if (needed <= capacity) return pointer; const auto next = std::next(chunk); if (next != arena->chunks.end() && !next->second.used && next->first == chunk->second.end && next->second.end - start >= needed) { const auto nextEnd = next->second.end; @@ -233,13 +229,12 @@ void* APS5_VABI sceLibcMspaceRealloc_nid_postfix(void* handle, void* pointer, st if (finish < nextEnd) AddFree(*arena, finish, nextEnd); arena->inUse += needed - capacity; arena->peakInUse = std::max(arena->peakInUse, arena->inUse); - arena->chunks[start] = {finish, true, size}; + arena->chunks[start] = {finish, true}; return pointer; } - const auto previousSize = chunk->second.requested; void* result = Allocate(arena, size, Granule); if (result) { - std::memcpy(result, pointer, previousSize); + std::memcpy(result, pointer, std::min(capacity, size)); Release(*arena, arena->chunks.find(start)); } return result; @@ -281,14 +276,11 @@ void* APS5_VABI sceLibcMspaceReallocalign_nid_postfix(void* handle, void* pointe const auto needed = AlignUp(size, Granule); if (needed < size) { Error(12); return nullptr; } const auto start = chunk->first; - if (needed <= chunk->second.end - start && (start & (effective - 1)) == 0) { - chunk->second.requested = size; - return pointer; - } - const auto previousSize = chunk->second.requested; + const auto capacity = chunk->second.end - start; + if (needed <= capacity && (start & (effective - 1)) == 0) return pointer; void* result = Allocate(arena, size, effective); if (result) { - std::memcpy(result, pointer, std::min(previousSize, size)); + std::memcpy(result, pointer, std::min(capacity, size)); Release(*arena, arena->chunks.find(start)); } return result; diff --git a/core/libs/tests/Mspace.cpp b/core/libs/tests/Mspace.cpp index 6244c1da1..de030efb0 100644 --- a/core/libs/tests/Mspace.cpp +++ b/core/libs/tests/Mspace.cpp @@ -79,9 +79,36 @@ static void CheckAdjacentBlocks() { Require(stats.currentInuseSize == static_cast(end(after) - static_cast(blocks[0]))); Require(sceLibcMspaceDestroy_nid_postfix(arena) == 0); } +static void CheckMovedBlockKeepsUsableBytes() { + alignas(32) static std::array storage{}; + void* arena = sceLibcMspaceCreate_nid_postfix("moved", storage.data(), storage.size(), 0); + Require(arena != nullptr); + const auto fill = [](void* block) { + const auto usable = sceLibcMspaceMallocUsableSize_nid_postfix(block); + Require(usable > 1); + for (std::size_t index = 0; index < usable; ++index) static_cast(block)[index] = static_cast(index + 1); + return usable; + }; + const auto kept = [](const void* block, std::size_t usable) { + for (std::size_t index = 0; index < usable; ++index) if (static_cast(block)[index] != static_cast(index + 1)) return false; + return true; + }; + void* block = sceLibcMspaceMalloc_nid_postfix(arena, 1); + const auto usable = fill(block); + Require(sceLibcMspaceMalloc_nid_postfix(arena, 1) != nullptr); + void* moved = sceLibcMspaceRealloc_nid_postfix(arena, block, 4096); + Require(moved != nullptr && moved != block && kept(moved, usable)); + void* other = sceLibcMspaceMalloc_nid_postfix(arena, 1); + const auto otherUsable = fill(other); + Require(sceLibcMspaceMalloc_nid_postfix(arena, 1) != nullptr); + void* realigned = sceLibcMspaceReallocalign_nid_postfix(arena, other, 4096, 256); + Require(realigned != nullptr && realigned != other && kept(realigned, otherUsable)); + Require(sceLibcMspaceDestroy_nid_postfix(arena) == 0); +} int main() { CheckAlignment(); CheckAdjacentBlocks(); + CheckMovedBlockKeepsUsableBytes(); alignas(16) std::array storage{}; void* arena = sceLibcMspaceCreate_nid_postfix("test", storage.data(), storage.size(), 0); Require(arena != nullptr);