diff --git a/core/libs/prx/libc/src/ApplicationHeap.cpp b/core/libs/prx/libc/src/ApplicationHeap.cpp index 6acd014d08..34b89291d4 100644 --- a/core/libs/prx/libc/src/ApplicationHeap.cpp +++ b/core/libs/prx/libc/src/ApplicationHeap.cpp @@ -202,6 +202,20 @@ void* ApplicationHeapAlign_nid_no_patch(std::size_t alignment, std::size_t bytes return pointer; } +extern "C" void* APS5_VABI scriptingGetMem_nid_postfix(std::size_t alignment, std::size_t bytes) { + alignment = std::max(alignment, 16); + if ((alignment & (alignment - 1)) != 0) return nullptr; + try { + return ApplicationHeapAlign_nid_no_patch(alignment, bytes); + } catch (const std::bad_alloc&) { + return nullptr; + } +} + +extern "C" void APS5_VABI scriptingFreeMem_nid_postfix(void* pointer) { + ApplicationHeapFree_nid_no_patch(pointer); +} + void* ApplicationHeapRealign_nid_no_patch(void* pointer, std::size_t bytes, std::size_t alignment) { if (bytes == 0) { ApplicationHeapFree_nid_no_patch(pointer); diff --git a/core/libs/tests/ApplicationHeap.cpp b/core/libs/tests/ApplicationHeap.cpp index 1886513ca0..f8a530d3b5 100644 --- a/core/libs/tests/ApplicationHeap.cpp +++ b/core/libs/tests/ApplicationHeap.cpp @@ -36,6 +36,8 @@ char* APS5_VABI strndup_nid_postfix(const char*, std::size_t); char* APS5_VABI getcwd_nid_postfix(char*, std::size_t); int* APS5_VABI __error_nid_postfix(); int APS5_VABI atexit_nid_postfix(void (APS5_VABI*)()); +void* APS5_VABI scriptingGetMem_nid_postfix(std::size_t, std::size_t); +void APS5_VABI scriptingFreeMem_nid_postfix(void*); } namespace { @@ -385,4 +387,15 @@ int main(int argc, char** argv) { *__error_nid_postfix() = 0; require(getcwd_nid_postfix(nullptr, 0) == nullptr && *__error_nid_postfix() == 12); fail = false; + const auto beforeScripting = frees; + scriptingFreeMem_nid_postfix(nullptr); + require(frees == beforeScripting); + require(scriptingGetMem_nid_postfix(0, 31) == storage.data() && lastAlignment == 16 && lastSize == 31); + require(scriptingGetMem_nid_postfix(64, 37) == storage.data() && lastAlignment == 64 && lastSize == 37); + scriptingFreeMem_nid_postfix(storage.data()); + require(frees == beforeScripting + 1); + require(scriptingGetMem_nid_postfix(24, 80) == nullptr && lastSize == 37); + fail = true; + require(scriptingGetMem_nid_postfix(16, 64) == nullptr); + fail = false; } diff --git a/docs/dev/debt/libc.md b/docs/dev/debt/libc.md index 50359fc84c..eb244ed912 100644 --- a/docs/dev/debt/libc.md +++ b/docs/dev/debt/libc.md @@ -3,6 +3,8 @@ ### Unknown function info - [fdopen](../../../core/libs/prx/libc/src/FileAndHeap.cpp) (libc) validates descriptor access modes as FreeBSD 11.4 [fdopen.c](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libc/stdio/fdopen.c) does: a requested mode incompatible with a descriptor not opened for both reading and writing returns null with `EINVAL`, leaving the descriptor open. Windows reads the handle's granted access through the same host helper as `fcntl(F_GETFL)`; a closed descriptor returns null with `EBADF`. Console behavior is unverified. +- [scriptingGetMem, scriptingFreeMem](../../../core/libs/prx/libc/src/ApplicationHeap.cpp) (libc) - runtime allocator hooks for Unity titles. The allocation signature `(alignment, size)`, minimum alignment 16 and null result for a non-power-of-two alignment follow [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/df5b9b92be7dfd463b47756b707d6d356a9f0550/src/libs/libKernel.cpp); the free hook's one-pointer signature follows [Raeen's recorded contract](https://github.com/Whoisraeen/Raeen/blob/2db56923204b89719916b95e29c2f3c4e1d9f90b/docs/unity-dlsym-blocker.md). Both use the registered application allocator. No console measurement; null allocation returns null and other allocator errors throw. + - [_Mtx_trylock](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `k6pGNMwJB08`) - returns busy for a non-recursive mutex already owned by the caller, assumed to match `_Mtx_lock`'s ownership handling; exact console behavior is unverified. - [nearbyintf](../../../core/libs/prx/libc/src/Math.cpp) (libc, NID `c+4r-T-tEIc`) uses the host rounding mode, not the console's; console rounding mode state remains unverified. - [_Thrd_sleep](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `jfRI3snge3o`) follows the Dinkumware threads library shipped with [Visual C++ 2013](https://github.com/adityaramesh/concurrency_runtime/tree/master/VS2013_SP2/crt/src/thr) (`xtime.c`) and C11 Annex K, without console verification. It reads a 16-byte xtime (64-bit seconds and nanoseconds) on the guest `CLOCK_REALTIME`, normalizes the nanoseconds and sleeps through `nanosleep`, retrying on `EINTR`, so it is a cancellation point; a null xtime or one whose normalization overflows throws. The console's `_Thrd_sleep` (disassembled from a title's `libc.prx`) also takes an optional `xtime*` of remaining time and returns `int`; here the sleep is never cut short, so it returns 0 and leaves the remaining time untouched.