test(libSceVrHand): add page-boundary coverage and qualify partial copyout in debt doc

This commit is contained in:
fogydes committed 2026-11-02 19:44:08 +05:30
1 parent aef43daa60
commit ebd650ca69
2 files changed
+59 -1

No files matched your search

+58
View File
@@ -3,6 +3,13 @@
#include <cstdint>
#include <cstdlib>
#include <cstring>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#endif
namespace {
@@ -11,6 +18,39 @@ void Require(bool value) { if (!value) std::abort(); }
constexpr int kErrInvalidArg = static_cast<int>(0x8a870006);
constexpr std::uint8_t kFill = 0xaa;
struct GuardedRegion {
std::size_t pageSize{0};
unsigned char* memory{nullptr};
GuardedRegion() {
#ifdef _WIN32
SYSTEM_INFO info{};
GetSystemInfo(&info);
pageSize = static_cast<std::size_t>(info.dwPageSize);
memory = static_cast<unsigned char*>(VirtualAlloc(nullptr, pageSize * 2, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
Require(memory != nullptr);
DWORD previous;
Require(VirtualProtect(memory + pageSize, pageSize, PAGE_NOACCESS, &previous) != 0);
#else
const long nativePageSize = sysconf(_SC_PAGESIZE);
Require(nativePageSize > 0);
pageSize = static_cast<std::size_t>(nativePageSize);
void* allocation = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Require(allocation != MAP_FAILED);
memory = static_cast<unsigned char*>(allocation);
Require(mprotect(memory + pageSize, pageSize, PROT_NONE) == 0);
#endif
}
~GuardedRegion() {
#ifdef _WIN32
VirtualFree(memory, 0, MEM_RELEASE);
#else
munmap(memory, pageSize * 2);
#endif
}
};
std::array<std::uint8_t, 0x40> ValidParam() {
std::array<std::uint8_t, 0x40> param{};
param[0] = 0x20;
@@ -40,6 +80,24 @@ int main() {
Require(sceVrHandQueryMemory(nullptr, out.data()) == kErrInvalidArg && Untouched(out));
Require(sceVrHandQueryMemory(param.data(), nullptr) == kErrInvalidArg);
GuardedRegion region;
auto* const boundaryParam = region.memory + region.pageSize - 0x20;
std::memset(boundaryParam, 0, 0x20);
boundaryParam[0] = 0x20;
out.fill(kFill);
Require(sceVrHandQueryMemory(boundaryParam, out.data()) == 0);
auto* const spanningParam = region.memory + region.pageSize - 0x10;
out.fill(kFill);
Require(sceVrHandQueryMemory(spanningParam, out.data()) == kErrInvalidArg && Untouched(out));
auto* const boundaryOut = region.memory + region.pageSize - 28;
std::memset(boundaryOut, kFill, 28);
Require(sceVrHandQueryMemory(param.data(), boundaryOut) == 0);
auto* const spanningOut = region.memory + region.pageSize - 8;
Require(sceVrHandQueryMemory(param.data(), spanningOut) == kErrInvalidArg);
for (const std::uint32_t size : {0u, 0x1fu, 0x21u, 0x40u, 0x120u, 0x10020u, 0x1000020u}) {
param = ValidParam();
std::memcpy(param.data(), &size, sizeof(size));
+1 -1
View File
@@ -3,4 +3,4 @@
### Unknown function info
- [sceVrHandFinalize, sceVrHandGetMesh, sceVrHandGetMeshSize, sceVrHandGetResult, sceVrHandInitialize, sceVrHandStart, sceVrHandStop](../../../core/libs/prx/libSceVrHand/Export.cpp) (libSceVrHand) - names and NIDs verified from pinned [ps5rs stubs](https://github.com/claimore22/ps5rs/tree/5f252a658ff470bcb2b6cd15205fd8ca64ae4477/data/stubs/by_library) (`libSceVrHand.txt`), with NID match confirmed via `tools/nid_names.py` `compute_nid`. Signatures, parameter layouts, and runtime behavior remain unverified; all paths throw through `NotImplemented_nid_no_patch`.
- [sceVrHandQueryMemory](../../../core/libs/prx/libSceVrHand/Export.cpp) (libSceVrHand) - the meaning of the parameter and output fields is unknown. It follows firmware 13.42's libSceVrHand.sprx, read from its disassembly and run natively on x86-64 (not a console): a null pointer, unreadable or unwritable pointers, a first 32-bit parameter word other than 0x20, or any nonzero parameter byte from offset 4 to 31 returns `0x8a870006` and writes nothing; otherwise it stores the 32-bit values 0x3c00000 and 0x10000 at output offsets 0 and 4, clears output bytes 8 to 27 and returns 0. Returning `0x8a870006` for unwritable or unreadable pointers is a defensive host-protection fallback; console behavior is unmeasured.
- [sceVrHandQueryMemory](../../../core/libs/prx/libSceVrHand/Export.cpp) (libSceVrHand) - the meaning of the parameter and output fields is unknown. It follows firmware 13.42's libSceVrHand.sprx, read from its disassembly and run natively on x86-64 (not a console): a null pointer, an unreadable parameter, a first 32-bit parameter word other than 0x20, or any nonzero parameter byte from offset 4 to 31 returns `0x8a870006` and writes nothing; an unwritable result pointer returns `0x8a870006` (with possible partial output on copy-out failure). Otherwise it stores the 32-bit values 0x3c00000 and 0x10000 at output offsets 0 and 4, clears output bytes 8 to 27 and returns 0. Returning `0x8a870006` for unwritable or unreadable pointers is a defensive host-protection fallback; console behavior is unmeasured.