diff --git a/core/libs/prx/libc/src/Mspace.cpp b/core/libs/prx/libc/src/Mspace.cpp index f2c91e33a4..01e8de2a22 100644 --- a/core/libs/prx/libc/src/Mspace.cpp +++ b/core/libs/prx/libc/src/Mspace.cpp @@ -314,6 +314,11 @@ void* APS5_VABI sceLibcPafMspaceMalloc_nid_postfix(void* handle, std::size_t siz return sceLibcMspaceMalloc_nid_postfix(handle, size); } +void* APS5_VABI sceLibcPafMspaceMemalign_nid_postfix(void* handle, std::size_t alignment, std::size_t size, const void* owner) { + (void)owner; + return sceLibcMspaceMemalign_nid_postfix(handle, alignment, size); +} + void APS5_VABI sceLibcPafMspaceFree_nid_postfix(void* handle, void* pointer, const void* owner) { (void)owner; sceLibcMspaceFree_nid_postfix(handle, pointer); diff --git a/docs/dev/debt/libc.md b/docs/dev/debt/libc.md index 3ae3b0cb34..b5bc56d6c6 100644 --- a/docs/dev/debt/libc.md +++ b/docs/dev/debt/libc.md @@ -17,7 +17,7 @@ - [Guest arena](../../../core/libs/prx/libc/src/GuestArena.cpp) (libc) - the application map area is assumed to end at 0xFC_0000_0000, as `SCE_KERNEL_APP_MAP_AREA_END_ADDR` does on the PS4. On Windows, host allocations made in the arena before libc loads stay, and a fixed guest mapping over one throws - [sceLibcInternalBacktraceForGame](../../../core/libs/prx/libc/src/HeapDiagnostics.cpp) (libSceLibcInternal, implemented in libc) - `(const char* heapName)` and its return follow the `libc.prx` ASTRO BOT (PPSA21564 01.007.000) bundles: its four calls (0x6801, 0x7F46, 0xE75E, 0xEE02) are in the `malloc_stats` and `sceLibcMspaceMallocStats` paths, each after a `[%s] ...` line printed with the same heap name buffer, and the caller ignores the result and continues. The console's backtrace output is not reproduced: the heap name and the guest return address are written to the host standard error - [sceLibcInternalHeapErrorReportForGame](../../../core/libs/prx/libc/src/HeapDiagnostics.cpp) (libSceLibcInternal, implemented in libc) - `(void* heap, void* block, uint32 error)` follows the same `libc.prx` (call at 0xF634): it passes the heap, the block and the nonzero result of its block check, and then calls a function that never returns, so the report only has to return. The meaning of the error values is unknown; the three values and the guest return address are written to the host standard error -- [sceLibcPafMspaceCreate, Destroy, Malloc, Free, Calloc, Realloc, Reallocalign, MallocStats and MallocStatsFast](../../../core/libs/prx/libc/src/Mspace.cpp) (libSceLibcInternal, implemented in libc) follow the console's `libSceLibcInternal.sprx` (SDK 4.5x build of `J03950001`, 0x5D680 to 0x5D770): each calls the same internal routine as its `sceLibcMspace` counterpart without the malloc callback hook those add, and `Reallocalign` takes the alignment before the size as `sceLibcMspaceReallocalign` does. `Create` takes a fifth argument, a pointer to a creation options block (a version word, a type of 1 or 2 at offset 2, a field at 0x10) that the `Mspace` form passes as null; a non-null block throws, as its meaning is unknown. `Malloc`, `Free`, `Calloc`, `Realloc` and `Reallocalign` take a trailing owner value that the console XORs with its block magic and stores in each block's footer, where the `Mspace` forms pass the heap itself. Footers are not modelled here, so the owner is ignored. Measured on a PS5 (firmware 13.60) from a homebrew payload, the calls with a matching owner behave as here, but the console ends the process when `Reallocalign` is given a block whose owner differs and when it resizes a block in place with an owner other than the heap, and `MallocStats` returns 1 instead of 0 while the heap holds blocks owned by something other than the heap; none of this is reproduced. `PafMspaceMemalign`, `PosixMemalign`, `MallocUsableSize`, `Trim`, `IsHeapEmpty`, `CheckMemoryBounds`, `ReportMemoryBlocks` and `GetFooterValue` are not implemented +- [sceLibcPafMspaceCreate, Destroy, Malloc, Memalign, Free, Calloc, Realloc, Reallocalign, MallocStats and MallocStatsFast](../../../core/libs/prx/libc/src/Mspace.cpp) - PAF exports delegate to `sceLibcMspace` without malloc hooks. `Memalign` is inferred as `(handle, alignment, size, owner)`, delegates to `sceLibcMspaceMemalign`, and is unverified on console. `Create` has an extra options pointer with a partly observed layout (version, type 1 or 2 at +2, field at +0x10); non-null options throw because the field's meaning is unknown. Allocation owners are ignored because block footers are not modelled. On PS5 firmware 13.60, heap-owner calls worked; wrong owners in `Reallocalign` or in-place `Realloc` terminate the process, and `MallocStats` returns 1 if non-heap-owned blocks exist. These owner results are not reproduced. `PosixMemalign`, `MallocUsableSize`, `Trim`, `IsHeapEmpty`, `CheckMemoryBounds`, `ReportMemoryBlocks` and `GetFooterValue` remain unimplemented. - [malloc_usable_size](../../../core/libs/prx/libc/src/ApplicationHeap.cpp) (libc) - with the default allocator it returns the size the block was requested with (the range registered for it), not the rounded-up chunk size Sony's allocator reports; both satisfy "at least the requested size", and bytes past the request would not be write-watched. With an application allocator it calls entry 9 of the replacement table (`malloc_usable_size` in KytyPS5's `MallocReplace` order) and throws when the table leaves it null, like `malloc_stats_fast` - [malloc_stats_fast](../../../core/libs/prx/libc/src/GuestHeap.cpp) (libc) - with the default allocator it fills the 0x28-byte managed-size block as `sceLibcMspaceMallocStatsFast` does, from the default heap's own accounting, not Sony's allocator: the system sizes count the 1 MiB spans of its small-block classes and its committed large blocks, cached free ones included, and the in-use sizes count each handed-out block at its size-class or 64 KiB-granule size, header included. A block size below 0x28 or a null pointer returns 22, as in the mspace version; the version field is not checked. Ship of Harkinian (PPSA99320) calls it about 10 s after start-up. - [malloc, calloc, realloc, memalign, aligned_alloc and reallocalign](../../../core/libs/prx/libc/src/FileAndHeap.cpp) (libc) - follow FreeBSD 11.4 `contrib/jemalloc/src/jemalloc.c` for failures, not measured on the console: a size the default heap rejects or the guest arena cannot place (including a `calloc` product that overflows) returns null with `errno` `ENOMEM`, and `memalign` and `aligned_alloc` return null with `EINVAL` for an alignment that is zero or not a power of two. FreeBSD's libc has no `memalign`, so setting `errno` there is assumed. A host commit failure for a block that fits in the arena (Windows `ERROR_NOT_ENOUGH_MEMORY`, `ERROR_OUTOFMEMORY` or `ERROR_COMMITMENT_LIMIT`, Linux `ENOMEM`) resets and releases the reserved range and returns null with `ENOMEM`; any other commit failure releases the range and throws. `reallocalign` returns null with `EINVAL` for an invalid alignment and `ENOMEM` like the others, which is an assumption as it is not in FreeBSD. `realloc(ptr, 0)` frees the block and returns null, where FreeBSD 11.4's jemalloc 4.5 resizes it to one byte and returns a block