mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
127 lines
8.8 KiB
C++
127 lines
8.8 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
struct Parameter { void* allocator; void* context; std::size_t fileBuffer; };
|
|
using InfoCallback = void (APS5_VABI*)(int, std::int32_t, void*);
|
|
extern "C" {
|
|
void APS5_VABI _ZN3sce4Json19InternalInitializerC1Ev(void*);
|
|
void APS5_VABI _ZN3sce4Json19InternalInitializerC2Ev(void*);
|
|
void APS5_VABI _ZN3sce4Json19InternalInitializerD1Ev(void*);
|
|
void APS5_VABI _ZN3sce4Json19InternalInitializerD2Ev(void*);
|
|
int APS5_VABI _ZN3sce4Json19InternalInitializer19terminate_staticlibEv(void*);
|
|
int APS5_VABI _ZN3sce4Json19InternalInitializer20initialize_staticlibEPKNS0_13InitParameterENS1_10InitOptionE(void*, const Parameter*, std::int32_t);
|
|
void APS5_VABI _ZN3sce4Json6StringC1EPKc(void*, const char*);
|
|
void APS5_VABI _ZN3sce4Json6StringD1Ev(void*);
|
|
void APS5_VABI _ZN3sce4Json6String7reserveEm(void*, std::size_t);
|
|
std::size_t APS5_VABI _ZNK3sce4Json6String8capacityEv(const void*);
|
|
void* APS5_VABI _ZN3sce4Json6MallocEm(std::size_t);
|
|
void APS5_VABI _ZN3sce4Json4FreeEPv(void*);
|
|
int APS5_VABI _ZN3sce4Json11Initializer24setAllocatorInfoCallBackEPFviNS0_9ValueTypeEPvES3_(void*, InfoCallback, void*);
|
|
void APS5_VABI _ZN3sce4Json12MemAllocatorD1Ev(void*);
|
|
void APS5_VABI _ZN3sce4Json12MemAllocatorD2Ev(void*);
|
|
void APS5_VABI _ZN3sce4Json11InitializerC1Ev(void*);
|
|
int APS5_VABI _ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(void*, const Parameter*);
|
|
int APS5_VABI _ZN3sce4Json11Initializer9terminateEv(void*);
|
|
}
|
|
static void Require(bool valid, const char* message) {
|
|
if (!valid) { std::fprintf(stderr, "%s\n", message); std::abort(); }
|
|
}
|
|
struct EntryTrace {
|
|
std::map<void*, std::size_t> live;
|
|
std::vector<std::size_t> requests;
|
|
std::vector<void*> frees;
|
|
void* expectedAllocator = nullptr;
|
|
bool reject = false;
|
|
int budget = -1;
|
|
unsigned notices = 0;
|
|
std::size_t failedSize = 0;
|
|
int notifiedState = 0;
|
|
int firstRequestState = 0;
|
|
int laterRequestState = 0;
|
|
};
|
|
static void APS5_VABI Info(int, std::int32_t, void*) { Require(false, "The reference allocator-info setter must not install or invoke the supplied callback"); }
|
|
static int InfoState() { return _ZN3sce4Json11Initializer24setAllocatorInfoCallBackEPFviNS0_9ValueTypeEPvES3_(nullptr, Info, nullptr); }
|
|
static void* APS5_VABI EntryAllocate(void* self, std::size_t size, void* context) {
|
|
auto& trace = *static_cast<EntryTrace*>(context);
|
|
Require(self == trace.expectedAllocator, "Allocation dispatch must preserve the allocator receiver and user context");
|
|
if (trace.requests.empty()) trace.firstRequestState = InfoState();
|
|
else trace.laterRequestState = InfoState();
|
|
trace.requests.push_back(size);
|
|
if (trace.reject || trace.budget == 0) return nullptr;
|
|
if (trace.budget > 0) --trace.budget;
|
|
void* pointer = std::malloc(size ? size : 1);
|
|
Require(pointer != nullptr && trace.live.emplace(pointer, size).second, "Tracking allocator must provide independently owned host storage");
|
|
return pointer;
|
|
}
|
|
static void APS5_VABI EntryFree(void* self, void* memory, void* context) {
|
|
auto& trace = *static_cast<EntryTrace*>(context);
|
|
Require(self == trace.expectedAllocator, "Free dispatch must preserve the allocator receiver and user context");
|
|
trace.frees.push_back(memory);
|
|
if (memory) { Require(trace.live.erase(memory) == 1, "Every allocation must be released exactly once through its allocator"); std::free(memory); }
|
|
}
|
|
static void APS5_VABI EntryNotify(void* self, int error, std::size_t size, void* context) {
|
|
auto& trace = *static_cast<EntryTrace*>(context);
|
|
Require(self == trace.expectedAllocator && static_cast<unsigned>(error) == 0x80848102, "Allocation failure must notify the owning allocator with the Json2 error");
|
|
++trace.notices; trace.failedSize = size; trace.notifiedState = InfoState();
|
|
}
|
|
int main() {
|
|
constexpr auto already = static_cast<int>(0x80848111);
|
|
constexpr auto missing = static_cast<int>(0x80848110);
|
|
constexpr auto invalid = static_cast<int>(0x80848120);
|
|
constexpr auto noMemory = static_cast<int>(0x80848102);
|
|
void* table[]{nullptr, nullptr, reinterpret_cast<void*>(&EntryAllocate), reinterpret_cast<void*>(&EntryFree), reinterpret_cast<void*>(&EntryNotify)};
|
|
void** allocator = table;
|
|
for (std::int32_t option : {0, 1, 2, -1}) {
|
|
for (int budget = 0; budget <= 12; ++budget) {
|
|
EntryTrace trace; trace.expectedAllocator = &allocator; trace.budget = budget;
|
|
Parameter parameter{&allocator, &trace, 8192};
|
|
std::uint8_t object[]{0xa5, 0x19, 0x28, 0x37};
|
|
if (budget % 2) _ZN3sce4Json19InternalInitializerC1Ev(object);
|
|
else _ZN3sce4Json19InternalInitializerC2Ev(object);
|
|
Require(object[0] == 0 && object[1] == 0x19 && object[2] == 0x28 && object[3] == 0x37, "Internal constructors must initialize only the active byte");
|
|
Require(_ZN3sce4Json19InternalInitializer19terminate_staticlibEv(object) == missing, "Inactive internal termination must return not-initialized");
|
|
Require(_ZN3sce4Json19InternalInitializer20initialize_staticlibEPKNS0_13InitParameterENS1_10InitOptionE(object, nullptr, option) == invalid, "Internal initialization must reject a missing parameter");
|
|
Parameter empty{};
|
|
Require(_ZN3sce4Json19InternalInitializer20initialize_staticlibEPKNS0_13InitParameterENS1_10InitOptionE(object, &empty, option) == noMemory, "Legacy internal initialization must report a missing allocator as out-of-memory");
|
|
const int result = _ZN3sce4Json19InternalInitializer20initialize_staticlibEPKNS0_13InitParameterENS1_10InitOptionE(object, ¶meter, option);
|
|
if (budget < 12) {
|
|
Require(result == noMemory && object[0] == 0 && trace.live.empty(), "Every required-resource allocation failure must roll back ownership and clear the active byte");
|
|
Require((budget == 0) == (trace.notices == 0), "The initial context failure must omit notification while resource failures notify");
|
|
trace.budget = -1;
|
|
Require(_ZN3sce4Json19InternalInitializer20initialize_staticlibEPKNS0_13InitParameterENS1_10InitOptionE(object, ¶meter, option) == 0, "Retry must succeed without reconstructing the failed internal initializer");
|
|
} else Require(result == 0, "Internal initialization must admit every option value after allocating all resources");
|
|
trace.budget = -1;
|
|
Require(object[0] == 1 && trace.live.size() == 12, "Internal initialization must own the same twelve required resources as legacy public initialization");
|
|
void* text = nullptr;
|
|
_ZN3sce4Json6StringC1EPKc(&text, "abc");
|
|
_ZN3sce4Json6String7reserveEm(&text, 5);
|
|
Require(_ZNK3sce4Json6String8capacityEv(&text) == 21, "Successful initialization must replace the requested growth option with the compiled SDK policy");
|
|
_ZN3sce4Json6StringD1Ev(&text);
|
|
for (std::int32_t rejectedOption : {0, 1, 2, -1}) {
|
|
std::uint8_t other = 0;
|
|
Require(_ZN3sce4Json19InternalInitializer20initialize_staticlibEPKNS0_13InitParameterENS1_10InitOptionE(&other, nullptr, rejectedOption) == already && other == 0 && object[0] == 1, "Global-context admission must precede parameter validation without taking ownership in another initializer");
|
|
_ZN3sce4Json6StringC1EPKc(&text, "abc");
|
|
_ZN3sce4Json6String7reserveEm(&text, 5);
|
|
Require(_ZNK3sce4Json6String8capacityEv(&text) == (rejectedOption == 1 ? 21 : 5), "Even a rejected internal initialization must update the string-growth option");
|
|
_ZN3sce4Json6StringD1Ev(&text);
|
|
Require(_ZN3sce4Json19InternalInitializer19terminate_staticlibEv(&other) == missing && trace.live.size() == 12, "An inactive initializer must not terminate another initializer's resources");
|
|
}
|
|
if (budget % 3 == 0) _ZN3sce4Json19InternalInitializerD1Ev(object);
|
|
else if (budget % 3 == 1) _ZN3sce4Json19InternalInitializerD2Ev(object);
|
|
else Require(_ZN3sce4Json19InternalInitializer19terminate_staticlibEv(object) == 0, "Explicit internal termination must succeed for its owning initializer");
|
|
Require(object[0] == 0 && object[1] == 0x19 && object[2] == 0x28 && object[3] == 0x37 && trace.live.empty(), "Every internal teardown entry point must release all resources exactly once and preserve adjacent bytes");
|
|
const auto frees = trace.frees.size();
|
|
_ZN3sce4Json19InternalInitializerD1Ev(object);
|
|
_ZN3sce4Json19InternalInitializerD2Ev(object);
|
|
Require(trace.frees.size() == frees && InfoState() == missing, "Repeated internal destruction must not dispatch stale frees");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|