Merge pull request #1621 from TheAggie/fix/libc-heap-32-byte-alignment

fix(libc): align guest heap allocations to 32 bytes
This commit is contained in:
Dean 2026-10-10 14:41:57 +13:00 committed by GitHub
commit e6f9348b31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 2 deletions

View File

@ -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<std::size_t>::max() - HeaderBytes - padding) throw std::length_error("guest heap allocation overflow");
std::size_t blockBytes = 0;
void* raw = rawAllocate(bytes + HeaderBytes + padding, blockBytes);

View File

@ -664,6 +664,24 @@ static void CheckSharedDirectMemoryLifecycle() {
Require(sceKernelReleaseDirectMemory(phys, page * 3) == 0);
}
static void CheckHeapAlignment() {
std::vector<std::pair<unsigned char*, std::size_t>> blocks;
for (std::size_t bytes = 1; bytes <= 600; ++bytes) blocks.emplace_back(static_cast<unsigned char*>(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<unsigned char*>(GuestHeap::GuestHeapAllocate_nid_postfix(bytes)), bytes);
auto* grown = static_cast<unsigned char*>(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<std::uintptr_t>(pointer) & 31u) == 0);
std::memset(pointer, static_cast<int>(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<unsigned char>(index & 0xffu));
GuestHeap::GuestHeapFree_nid_postfix(pointer);
}
}
static void CheckHeapAfterMappingReuse() {
constexpr std::size_t bytes = 0x30000;
auto* pointer = static_cast<unsigned char*>(GuestHeap::GuestHeapAllocate_nid_postfix(bytes));
@ -1080,6 +1098,7 @@ int main() {
CheckSharedDirectMemoryLifecycle();
CheckGetDirectMemoryType();
CheckMtypeprotect();
CheckHeapAlignment();
CheckHeapAfterMappingReuse();
#ifdef _WIN32
CheckNoOverwriteRejectsHostOccupiedMapping();