fix(libkernel): let munmap succeed over a range with nothing mapped
munmap and sceKernelMunmap over a range in which no page is mapped failed: munmap returned EINVAL and sceKernelMunmap let the registry's exception escape. Both now return 0. The console returns 0 for sceKernelMunmap of a range it just unmapped and of a never-mapped address, and EINVAL only for a zero length, as measured by prosper's console oracle (kernelx.golden.tsv, kx_fmem_unmap_again, kx_fmem_munmap_unmapped). The other half of #3196, a range with an unmapped page in the middle, is already fixed on main by 04ed61957; the test covers both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a11c8f7f70
commit
9d96752fcd
|
|
@ -923,6 +923,7 @@ int DoMunmap(void* addr, size_t len) {
|
|||
Trace("unmap %p+0x%zx", addr, len);
|
||||
if (len == 0 || (len & (PS5_PAGE_SIZE - 1)) != 0 || !addr) return SCE_KERNEL_ERROR_EINVAL;
|
||||
GuestAllocations::Mutation mutation;
|
||||
if (!mutation.Overlaps(addr, len)) return 0;
|
||||
UnmapRegistered(mutation, addr, len);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1672,6 +1672,28 @@ static void CheckAvailableDirectMemoryIsLargestFreeBlock() {
|
|||
Require(start == top && size == static_cast<std::size_t>(window));
|
||||
}
|
||||
|
||||
static void CheckMunmapOverUnmappedPages() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
const auto failed = reinterpret_cast<void*>(static_cast<std::uintptr_t>(-1));
|
||||
void* raw = mmap_nid_postfix(nullptr, page * 3, 3, 0x1002, -1, 0);
|
||||
Require(raw != failed);
|
||||
auto* memory = static_cast<unsigned char*>(raw);
|
||||
memory[0] = 1;
|
||||
memory[page * 2] = 2;
|
||||
Require(munmap_nid_postfix(memory + page, page) == 0);
|
||||
Require(munmap_nid_postfix(memory, page * 3) == 0);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
Require(!mutation.Overlaps(memory, page * 3));
|
||||
}
|
||||
VirtualQueryInfo info{};
|
||||
Require(sceKernelVirtualQuery(memory, 0, &info, sizeof(info)) == SCE_KERNEL_ERROR_EACCES);
|
||||
Require(sceKernelVirtualQuery(memory + page * 2, 0, &info, sizeof(info)) == SCE_KERNEL_ERROR_EACCES);
|
||||
Require(munmap_nid_postfix(memory, page * 3) == 0);
|
||||
Require(sceKernelMunmap(memory, page * 3) == 0);
|
||||
Require(sceKernelMunmap(memory, 0) == SCE_KERNEL_ERROR_EINVAL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
#ifdef _WIN32
|
||||
_putenv_s("APS5_PIN_WAIT_MS", "1000");
|
||||
|
|
@ -1681,6 +1703,7 @@ int main() {
|
|||
CheckVirtualQueryForNonReadableGuestRange();
|
||||
CheckReleaseFlexibleMemory();
|
||||
CheckVirtualQueryPartialMunmap();
|
||||
CheckMunmapOverUnmappedPages();
|
||||
CheckNamedAndHintedMappings();
|
||||
CheckInternalNamedFlexibleMapping();
|
||||
CheckBatchMapStopsAtInvalidEntry();
|
||||
|
|
@ -1793,7 +1816,7 @@ int main() {
|
|||
Require(munmap_nid_postfix(memory, page) == 0);
|
||||
Require(memory[page * 2] == 73);
|
||||
Require(munmap_nid_postfix(memory + page * 2, page) == 0);
|
||||
Require(munmap_nid_postfix(memory, page) == -1);
|
||||
Require(munmap_nid_postfix(memory, page) == 0);
|
||||
Require(madvise_nid_postfix(memory, page, 4) == 0);
|
||||
*__error_nid_postfix() = 0;
|
||||
Require(mprotect_nid_postfix(memory, page, 1) == -1 && *__error_nid_postfix() == 22);
|
||||
|
|
|
|||
Loading…
Reference in New Issue