#include "prx/libSceRandom/include/Api.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #include #endif static void Require(bool value, std::source_location location = std::source_location::current()) { if (!value) { std::fprintf(stderr, "boundary check failed at line %u\n", location.line()); std::abort(); } } class Guarded { unsigned char* memory; std::size_t page; std::size_t writable; public: explicit Guarded(std::size_t capacity = 1) { #ifdef _WIN32 SYSTEM_INFO info{}; GetSystemInfo(&info); page = info.dwPageSize; #else const long size = sysconf(_SC_PAGESIZE); Require(size > 0); page = static_cast(size); #endif writable = ((capacity + 128 + page - 1) / page) * page; #ifdef _WIN32 memory = static_cast(VirtualAlloc(nullptr, writable + page * 2, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS)); Require(memory != nullptr); #else memory = static_cast(mmap(nullptr, writable + page * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); Require(memory != MAP_FAILED); #endif Reset(); } ~Guarded() { #ifdef _WIN32 Require(VirtualFree(memory, 0, MEM_RELEASE) != 0); #else Require(munmap(memory, writable + page * 2) == 0); #endif } Guarded(const Guarded&) = delete; Guarded& operator=(const Guarded&) = delete; void Protect(bool readOnly) { #ifdef _WIN32 DWORD previous; Require(VirtualProtect(memory + page, writable, readOnly ? PAGE_READONLY : PAGE_READWRITE, &previous) != 0); #else Require(mprotect(memory + page, writable, readOnly ? PROT_READ : PROT_READ | PROT_WRITE) == 0); #endif } void Reset() { Protect(false); std::memset(memory + page, 0xa5, writable); } unsigned char* End(std::size_t count) { Require(count + 64 <= writable); return memory + page + writable - (std::max)(count, std::size_t{1}); } void Prefix(const void* address) const { const auto* bytes = static_cast(address); for (int index = 1; index <= 32; ++index) Require(bytes[-index] == 0xa5); } }; int main() { Guarded output(65); for (std::size_t size = 0; size <= 64; ++size) { output.Reset(); auto* bytes = output.End(size); Require(sceRandomGetRandomNumber(bytes, size) == 0); output.Prefix(bytes); if (size == 0) Require(bytes[0] == 0xa5); } for (const auto size : {std::size_t{65}, SIZE_MAX}) { output.Reset(); auto* bytes = output.End(65); Require(sceRandomGetRandomNumber(bytes, size) == static_cast(0x817c0016)); Require(std::all_of(bytes, bytes + 65, [](auto value) { return value == 0xa5; })); output.Prefix(bytes); } std::puts("65 valid random extents and 2 rejected lengths passed"); }