From e9fa393546e7dde497b75f020d58372b053a78b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Oct 2026 22:05:55 +0100 Subject: [PATCH] Kernel: Match GetModuleIdList and heap allocation to hardware pspautotests modules/idlist shows that sceKernelGetModuleIdList still writes a partial entry at the end of the buffer (a size of 6 gives two entries), which the previous commit had stopped. A NULL buffer or a negative size returns ILLEGAL_ADDR without writing the count. sysmem/kernel/heap shows sceKernelAllocHeapMemory returning null for sizes near 4GB, rather than wrapping. The WithOption variant already checked this. The plain one now does too. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceKernelHeap.cpp | 5 ++++- Core/HLE/sceKernelModule.cpp | 14 ++++++++------ pspautotests | 2 +- test.py | 1 + 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 44e6e92961..54c85ce41c 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -102,7 +102,10 @@ static int sceKernelAllocHeapMemory(int heapId, int size) { return hleLogError(Log::sceKernel, 0, "invalid heapId"); } - // There's 8 bytes at the end of every block, reserved. + // There's 8 bytes at the end of every block, reserved. Don't let that wrap (sysmem/kernel/heap). + if ((u32)size > 0xFFFFFF00) { + return hleLogError(Log::sceKernel, 0, "invalid size %08x", size); + } u32 memSize = KERNEL_HEAP_BLOCK_HEADER_SIZE + size; u32 addr = heap->alloc.Alloc(memSize, true); if (addr == (u32)-1) { diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 54cb6bc162..54131b836e 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -3838,8 +3838,12 @@ static u32 sceKernelQueryModuleInfo(u32 uid, u32 infoAddr) static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 idCountAddr) { - ERROR_LOG(Log::sceModule, "UNTESTED sceKernelGetModuleIdList(%08x, %i, %08x)", resultBuffer, resultBufferSize, idCountAddr); - + // pspautotests modules/idlist: the size is in bytes, a partial entry at the end still gets + // written, and the count covers every module whether it fit or not. + if (resultBuffer == 0 || (int)resultBufferSize < 0) { + return hleLogError(Log::sceModule, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad buffer"); + } + int idCount = 0; u32 resultBufferOffset = 0; @@ -3850,8 +3854,7 @@ static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 continue; } if (!module->isFake || liedAboutThisModule(module)) { - // Only whole entries. - if (resultBufferOffset + 4 <= resultBufferSize) { + if (resultBufferOffset < resultBufferSize) { Memory::WriteOrException_U32(module->GetUID(), resultBuffer + resultBufferOffset); resultBufferOffset += 4; } @@ -3860,8 +3863,7 @@ static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 } Memory::WriteOrException_U32(idCount, idCountAddr); - - return hleNoLog(0); + return hleLogDebug(Log::sceModule, 0); } bool DescribeModuleAddress(u32 address, char *buffer, size_t bufferSize) { diff --git a/pspautotests b/pspautotests index e26ed03caa..88e64dd037 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit e26ed03caaa02873159a636b9f35ba81fe08ccd3 +Subproject commit 88e64dd03767cd69e32e2197afb84f38cf7aba20 diff --git a/test.py b/test.py index dcf8183209..8ec831539f 100755 --- a/test.py +++ b/test.py @@ -347,6 +347,7 @@ tests_good = [ "misc/deadbeef", "modules/cutrel/cutrel", "modules/cutrel/kernel/cutrel", + "modules/idlist/idlist", "modules/loadrace/loadrace", "modules/startoptions/startoptions", "modules/unresolved/unresolved",