diff --git a/core/libs/prx/libc/src/GuestHeap.cpp b/core/libs/prx/libc/src/GuestHeap.cpp index ae9d1674c..89efffce7 100644 --- a/core/libs/prx/libc/src/GuestHeap.cpp +++ b/core/libs/prx/libc/src/GuestHeap.cpp @@ -24,7 +24,8 @@ namespace { // Each block is preceded by a header holding the raw block address and its size in bytes. constexpr std::size_t HeaderBytes = 2 * sizeof(void*); -constexpr std::size_t MinimumAlignment = 16; +constexpr std::size_t RawAlignment = 16; +constexpr std::size_t MinimumAlignment = 32; constexpr std::size_t PageBytes = 0x4000; constexpr std::size_t SpanBytes = 1u << 20; constexpr std::size_t MaximumSmallBytes = 64u * 1024u; @@ -200,7 +201,7 @@ void rawFree(void* raw, std::size_t blockBytes) { void* allocate(GuestAllocations::Mutation& mutation, std::size_t alignment, std::size_t bytes) { if (alignment == 0 || (alignment & (alignment - 1)) != 0) throw std::invalid_argument("invalid guest heap alignment"); alignment = std::max(alignment, MinimumAlignment); - const std::size_t padding = alignment > MinimumAlignment ? alignment : 0; + const std::size_t padding = alignment > RawAlignment ? alignment : 0; if (bytes > std::numeric_limits::max() - HeaderBytes - padding) throw std::length_error("guest heap allocation overflow"); std::size_t blockBytes = 0; void* raw = rawAllocate(bytes + HeaderBytes + padding, blockBytes); diff --git a/core/libs/tests/GuestMemory.cpp b/core/libs/tests/GuestMemory.cpp index 892cefb40..d3b10f393 100644 --- a/core/libs/tests/GuestMemory.cpp +++ b/core/libs/tests/GuestMemory.cpp @@ -664,6 +664,24 @@ static void CheckSharedDirectMemoryLifecycle() { Require(sceKernelReleaseDirectMemory(phys, page * 3) == 0); } +static void CheckHeapAlignment() { + std::vector> blocks; + for (std::size_t bytes = 1; bytes <= 600; ++bytes) blocks.emplace_back(static_cast(GuestHeap::GuestHeapAllocate_nid_postfix(bytes)), bytes); + for (const std::size_t bytes : {std::size_t{4000}, std::size_t{70000}, std::size_t{0x30000}}) blocks.emplace_back(static_cast(GuestHeap::GuestHeapAllocate_nid_postfix(bytes)), bytes); + auto* grown = static_cast(GuestHeap::GuestHeapReallocate_nid_postfix(GuestHeap::GuestHeapAllocate_nid_postfix(8), 333)); + blocks.emplace_back(grown, 333); + for (std::size_t index = 0; index < blocks.size(); ++index) { + const auto [pointer, bytes] = blocks[index]; + Require((reinterpret_cast(pointer) & 31u) == 0); + std::memset(pointer, static_cast(index & 0xffu), bytes); + } + for (std::size_t index = 0; index < blocks.size(); ++index) { + const auto [pointer, bytes] = blocks[index]; + for (std::size_t at = 0; at < bytes; ++at) Require(pointer[at] == static_cast(index & 0xffu)); + GuestHeap::GuestHeapFree_nid_postfix(pointer); + } +} + static void CheckHeapAfterMappingReuse() { constexpr std::size_t bytes = 0x30000; auto* pointer = static_cast(GuestHeap::GuestHeapAllocate_nid_postfix(bytes)); @@ -1080,6 +1098,7 @@ int main() { CheckSharedDirectMemoryLifecycle(); CheckGetDirectMemoryType(); CheckMtypeprotect(); + CheckHeapAlignment(); CheckHeapAfterMappingReuse(); #ifdef _WIN32 CheckNoOverwriteRejectsHostOccupiedMapping();