#include "prx/libSceJson2/include/Api.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include #include #include #include #include #include using namespace SceJson2; struct Parameter { void* allocator; void* context; std::size_t bufferSize; }; using Handler = const Value& (APS5_VABI*)(ValueType, const Value*, const Value*, void*); using ReadCallback = int (APS5_VABI*)(char&, void*); using NullHandler = const Value& (APS5_VABI*)(ValueType, const Value*, void*); static void Require(bool valid, const char* message) { if (!valid) { std::fprintf(stderr, "%s\n", message); std::abort(); } } struct LegacyTrace { std::map guest; std::map heap; int budget = -1; int heapBudget = -1; bool once = false; std::vector requests; std::map guestGenerations; std::map heapGenerations; std::size_t generation = 0; unsigned notifications = 0; void (*onNotify)(void*) = nullptr; void* noticeContext = nullptr; }; static LegacyTrace* HeapTrace = nullptr; extern "C" const void* ApplicationProcessParameters_nid_no_patch() { alignas(8) static const std::uint32_t parameters[]{0, 0, 0, 0, 0x05000000, 0}; return parameters; } extern "C" void* APS5_VABI _Znwm_nid_postfix(std::size_t bytes) { Require(HeapTrace != nullptr, "Heap allocation requires its owning trace"); if (HeapTrace->heapBudget == 0) throw std::bad_alloc(); if (HeapTrace->heapBudget > 0) --HeapTrace->heapBudget; void* memory = std::malloc(bytes); if (!memory) throw std::bad_alloc(); std::memset(memory, 0xa5, bytes); Require(HeapTrace && bytes == 56, "Legacy map nodes must use the actual libc new allocation boundary"); Require(HeapTrace->heap.emplace(memory, bytes).second && HeapTrace->heapGenerations.emplace(memory, ++HeapTrace->generation).second, "Legacy libc allocations must own distinct live generations"); return memory; } extern "C" void APS5_VABI _ZdlPv_nid_postfix(void* memory) { Require(HeapTrace && HeapTrace->heap.erase(memory) == 1 && HeapTrace->heapGenerations.erase(memory) == 1, "Legacy map nodes must return through libc delete"); std::free(memory); } static void* APS5_VABI AllocateLegacy(void*, std::size_t bytes, void* context) { auto& trace = *static_cast(context); trace.requests.push_back(bytes); if (trace.budget == 0) { if (trace.once) trace.budget = -1; return nullptr; } if (trace.budget > 0) --trace.budget; void* memory = std::malloc(bytes); Require(memory != nullptr, "Tracking allocator requires host memory"); std::memset(memory, 0xa5, bytes); Require(trace.guest.emplace(memory, bytes).second && trace.guestGenerations.emplace(memory, ++trace.generation).second, "Legacy guest allocations must own distinct live generations"); return memory; } static void APS5_VABI FreeLegacy(void*, void* memory, void* context) { if (!memory) return; Require(static_cast(context)->guest.erase(memory) == 1 && static_cast(context)->guestGenerations.erase(memory) == 1, "Legacy metadata must return through its owning allocator"); std::free(memory); } static void APS5_VABI NotifyLegacy(void*, int error, std::size_t bytes, void* context) { Require(static_cast(error) == 0x80848102 && bytes == static_cast(context)->requests.back(), "Legacy allocation failure must identify its actual rejected request"); auto& trace = *static_cast(context); ++trace.notifications; if (const auto action = trace.onNotify) { trace.onNotify = nullptr; action(trace.noticeContext); } } static void* const LegacyVtable[]{nullptr, nullptr, reinterpret_cast(AllocateLegacy), reinterpret_cast(FreeLegacy), reinterpret_cast(NotifyLegacy)}; struct LegacyAllocator { void* const* vtable = LegacyVtable; }; struct LegacyNode { LegacyNode* parent; LegacyNode* left; LegacyNode* right; const Value* key; Handler callback; void* context; std::uint8_t color; std::uint8_t nil; std::uint8_t reserved[6]; }; struct LegacyHeader { LegacyNode* head; std::size_t count; std::uint64_t reserved; }; static_assert(sizeof(LegacyNode) == 56 && sizeof(LegacyHeader) == 24); struct Context { Value replacement{}; unsigned calls = 0; const Value* source = nullptr; const Value* parent = nullptr; }; static const Value& APS5_VABI RecoverLegacy(ValueType type, const Value* source, const Value* parent, void* context) { auto& result = *static_cast(context); Require(type == 1, "Legacy mismatch dispatch must identify the requested type"); ++result.calls; result.source = source; result.parent = parent; return result.replacement; } static void ParseLegacy(Value& value, const char* text = "9") { _ZN3sce4Json5ValueC1Ev(&value); Require(_ZN3sce4Json6Parser5parseERNS0_5ValueEPKcm(&value, text, std::strlen(text)) == 0, "Prepare legacy root auxiliary metadata"); } static void CheckMap(const LegacyTrace& trace, const std::map& entries) { const LegacyHeader* header = nullptr; for (const auto& [memory, size] : trace.guest) { if (size != 24) continue; void* head = nullptr; std::memcpy(&head, memory, sizeof(head)); if (trace.heap.contains(head)) { Require(!header, "Legacy registration must use one shared map header"); header = reinterpret_cast(memory); } } Require(header && header->count == entries.size() && header->reserved == UINT64_C(0xa5a5a5a5a5a5a5a5), "Legacy map header must preserve count and reserved bytes"); auto* head = header->head; Require(head->nil == 1 && head->color == 0 && head->parent->color == 0, "Legacy sentinel and root must be black"); auto expected = entries.begin(); std::function visit = [&](const LegacyNode* node, const LegacyNode* parent) -> unsigned { if (node == head) return 1; Require(trace.heap.contains(const_cast(node)) && node->parent == parent && !node->nil && node->color <= 1, "Legacy nodes must retain their libc ownership and parent link"); Require(!node->color || (!node->left->color && !node->right->color), "Legacy red nodes must have black children"); const auto left = visit(node->left, node); Require(expected != entries.end() && node->key == expected->first && node->callback == (expected->second ? RecoverLegacy : nullptr) && node->context == expected->second, "Legacy map entries must preserve sorted keys and callback identity"); ++expected; const auto right = visit(node->right, node); Require(left == right, "Legacy tree paths must preserve black height"); return left + !node->color; }; visit(head->parent, head); Require(expected == entries.end() && trace.heap.size() == entries.size() + 1, "Legacy map must retain only its actual sentinel and entry nodes"); } struct NullContext { const Value* other; Context* replacement; }; static const Value& APS5_VABI RecoverLegacyNull(ValueType requested, const Value* parent, void* context) { auto& value = *static_cast(context); Require(requested == 1 && !parent && *_ZNK3sce4Json5Value10getBooleanEv(value.other), "Legacy null recovery must allow independent mismatch recovery before the reentry guard"); return value.replacement->replacement; } struct LegacySnapshot { void* pointer; std::size_t generation; std::vector bytes; }; static void CheckPairCopies(LegacyTrace& trace, Context& context) { const auto guestBaseline = trace.guestGenerations, heapBaseline = trace.heapGenerations; for (bool text : {false, true}) for (bool once : {false, true}) for (unsigned alias = 0; alias < 2; ++alias) for (int budget = 0; budget <= (text ? 5 : 2); ++budget) { Value source{}; ParseLegacy(source, text ? "\"abc\"" : "9"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0, "Register the actual legacy Pair source map record"); std::vector sourceAllocations; for (const auto& [pointer, generation] : trace.guestGenerations) { if (guestBaseline.contains(pointer)) continue; const auto* bytes = reinterpret_cast(pointer); sourceAllocations.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } const LegacyNode* sourceNode = nullptr; for (const auto& [pointer, size] : trace.heap) { const auto* node = reinterpret_cast(pointer); if (!node->nil && node->key == &source) sourceNode = node; } Require(sourceNode && sourceNode->callback == RecoverLegacy && sourceNode->context == &context, "Pair copying requires an independently owned source callback record"); const auto sourceGeneration = trace.heapGenerations.at(const_cast(sourceNode)); const Value sourceValue = source; String key{}; _ZN3sce4Json6StringC1EPKc(&key, "key"); Pair pair; std::memset(&pair, 0xa5, sizeof(pair)); const auto requests = trace.requests.size(); const auto notices = trace.notifications; trace.budget = budget; trace.once = once; if (alias) _ZN3sce4Json6Object4PairC2ERKNS0_6StringERKNS0_5ValueE(&pair, &key, &source); else _ZN3sce4Json6Object4PairC1ERKNS0_6StringERKNS0_5ValueE(&pair, &key, &source); trace.budget = -1; trace.once = false; std::vector expected{24}; if (budget > 0) expected.push_back(4); if (text) { expected.push_back(8); if ((once && budget < 2) || budget >= 3) expected.push_back(24); if ((once && budget < 2) || budget >= 4) expected.push_back(4); } Require(std::vector(trace.requests.begin() + requests, trace.requests.end()) == expected, "Legacy Pair failure must preserve the measured key, Value handle, text header and character request order"); const unsigned failed = text ? (once ? unsigned(budget < 5) : budget < 2 ? 2u : unsigned(budget < 5)) : unsigned(budget < 2); Require(trace.notifications == notices + failed, "Legacy Pair copies must notify every admitted allocation failure"); const int expectedType = text ? ((once && budget < 2) || budget >= 4 ? 5 : 0) : 3; Require(pair.reserved == UINT64_C(0xa5a5a5a5a5a5a5a5) && !pair.value.parent && !pair.value.auxiliary && pair.value.type == expectedType, "Legacy Pair copies must preserve inactive Pair bytes and retain independent Value ownership"); Require(std::strcmp(_ZNK3sce4Json6String5c_strEv(&pair.key), budget < 2 ? "" : "key") == 0, "Legacy Pair key failures must preserve the measured empty or completed key"); if (expectedType == 5) Require(pair.value.payload && std::strcmp(_ZNK3sce4Json6String5c_strEv(reinterpret_cast(pair.value.payload)), budget == 4 ? "" : "abc") == 0, "Legacy Pair string failures must preserve the admitted partial text"); if (!text) Require(pair.value.payload == 9, "Failed Pair key allocation must not suppress scalar copying"); CheckMap(trace, {{&source, &context}, {&pair.value, &context}}); const auto calls = context.calls; Require(_ZNK3sce4Json5Value10getBooleanEv(&pair.value) == reinterpret_cast(&context.replacement.payload) && context.calls == calls + 1 && context.source == &pair.value && !context.parent, "Every partial legacy Pair must retain its independently copied map callback and exact borrowed replacement identity"); if (alias) _ZN3sce4Json6Object4PairD2Ev(&pair); else _ZN3sce4Json6Object4PairD1Ev(&pair); CheckMap(trace, {{&source, &context}}); Require(std::memcmp(&source, &sourceValue, sizeof(source)) == 0 && trace.heapGenerations.at(const_cast(sourceNode)) == sourceGeneration && sourceNode->callback == RecoverLegacy && sourceNode->context == &context, "Pair cleanup must preserve source bytes and its original callback-record generation"); for (const auto& snapshot : sourceAllocations) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Failed Pair copies must preserve all source guest allocation generations and bytes"); Require(_ZNK3sce4Json5Value10getBooleanEv(&source) == reinterpret_cast(&context.replacement.payload) && context.source == &source && !context.parent, "Source callbacks must remain usable after failed Pair copy teardown"); _ZN3sce4Json6StringD1Ev(&key); _ZN3sce4Json5ValueD1Ev(&source); CheckMap(trace, {}); Require(trace.guestGenerations == guestBaseline && trace.heapGenerations == heapBaseline, "Legacy Pair copies must reclaim every new generation in both allocator domains"); } } struct LegacyArrayLink { LegacyArrayLink* previous; LegacyArrayLink* next; Value value; }; struct LegacyArrayHeader { LegacyArrayLink* head; std::size_t count; std::uint64_t reserved; }; struct LegacyTreeLink { LegacyTreeLink* parent; LegacyTreeLink* left; LegacyTreeLink* right; unsigned char key[24]; Pair pair; unsigned char color; unsigned char nil; unsigned char reserved[6]; }; struct LegacyTreeHeader { LegacyTreeLink* head; std::size_t count; std::uint64_t reserved; }; static_assert(sizeof(LegacyArrayHeader) == 24 && sizeof(LegacyTreeHeader) == 24 && sizeof(LegacyTreeLink) == 104); static void CollectionShape(const Value& value, const Value* parent, std::string& output, std::vector& values); static void CollectionTreeShape(const LegacyTreeLink* node, const Value* parent, std::string& output, std::vector& values) { if (node->nil) return; CollectionTreeShape(node->left, parent, output, values); output += "k=" + std::string(*reinterpret_cast(node->key)) + "/q=" + _ZNK3sce4Json6String5c_strEv(&node->pair.key) + "/"; CollectionShape(node->pair.value, parent, output, values); CollectionTreeShape(node->right, parent, output, values); } static void CollectionShape(const Value& value, const Value* parent, std::string& output, std::vector& values) { values.push_back(&value); output += std::to_string(value.type) + ":" + std::to_string(value.parent ? value.parent == parent ? 1 : 2 : 0); if (value.type > 0 && value.type < 5) output += "=" + std::to_string(value.payload); if (value.type == 5) output += "s=" + std::string(value.payload ? _ZNK3sce4Json6String5c_strEv(reinterpret_cast(value.payload)) : ""); if (value.type == 6) { auto* header = value.payload ? *reinterpret_cast(value.payload) : nullptr; if (!header) { output += "x;"; return; } output += "a" + std::to_string(header->count) + "["; if (!header->head) output += "missing"; else for (auto* node = header->head->next; node != header->head; node = node->next) CollectionShape(node->value, &value, output, values); output += "]"; } if (value.type == 7) { auto* header = value.payload ? *reinterpret_cast(value.payload) : nullptr; if (!header) { output += "x;"; return; } output += "o" + std::to_string(header->count) + "{"; if (!header->head) output += "missing"; else CollectionTreeShape(header->head->parent, &value, output, values); output += "}"; } output += ";"; } struct LegacyCollectionCase { unsigned source; bool once; int budget; unsigned notifications; std::size_t requests; std::uint64_t requestOrder; const char* key; const char* shape; }; static const LegacyCollectionCase CollectionCases[]{ {0, 0, 0, 2, 2, UINT64_C(0x08842007b530c95d), "", "0:0;"}, {0, 0, 1, 2, 3, UINT64_C(0xa922fa18e1c37583), "", "0:0;"}, {0, 0, 2, 1, 3, UINT64_C(0xa922fa18e1c37583), "key", "0:0;"}, {0, 0, 3, 1, 4, UINT64_C(0x29e493479f20d661), "key", "0:0;"}, {0, 0, 4, 2, 6, UINT64_C(0x231a8cd446ee0ac9), "key", "6:0a0[missing];"}, {0, 0, 5, 1, 6, UINT64_C(0x231a8cd446ee0ac9), "key", "6:0a0[missing];"}, {0, 0, 6, 1, 7, UINT64_C(0x942845b4867ca51b), "key", "6:0a0[];"}, {0, 0, 7, 1, 8, UINT64_C(0x3d1384c085cc7f49), "key", "6:0a1[0:0;];"}, {0, 0, 8, 1, 9, UINT64_C(0x94a9e4235a7c56a3), "key", "6:0a1[0:0;];"}, {0, 0, 9, 1, 10, UINT64_C(0x19057312c1477af1), "key", "6:0a1[0:0;];"}, {0, 0, 10, 1, 11, UINT64_C(0xcbbd21de6c7551fb), "key", "6:0a1[7:0o0{missing};];"}, {0, 0, 11, 1, 12, UINT64_C(0xa7b21ff24b599cc9), "key", "6:0a1[7:0o0{};];"}, {0, 0, 12, 3, 15, UINT64_C(0x44ba72eae582feb9), "key", "6:0a1[7:0o1{k=/q=/0:0;};];"}, {0, 0, 13, 2, 15, UINT64_C(0x44ba72eae582feb9), "key", "6:0a1[7:0o1{k=s/q=/0:0;};];"}, {0, 0, 14, 2, 16, UINT64_C(0x4be45a23fda819b9), "key", "6:0a1[7:0o1{k=s/q=/0:0;};];"}, {0, 0, 15, 1, 16, UINT64_C(0x4be45a23fda819b9), "key", "6:0a1[7:0o1{k=s/q=s/0:0;};];"}, {0, 0, 16, 1, 17, UINT64_C(0x9d1ecc2804a38c93), "key", "6:0a1[7:0o1{k=s/q=s/0:0;};];"}, {0, 0, 17, 1, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=s/q=s/5:0s=;};];"}, {0, 0, 18, 0, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=s/q=s/5:0s=t;};];"}, {0, 1, 0, 1, 17, UINT64_C(0xd9fd6582200984bd), "", "6:0a1[7:0o1{k=s/q=s/5:0s=t;};];"}, {0, 1, 1, 1, 18, UINT64_C(0x9ee178ffe1e7da63), "", "6:0a1[7:0o1{k=s/q=s/5:0s=t;};];"}, {0, 1, 2, 1, 3, UINT64_C(0xa922fa18e1c37583), "key", "0:0;"}, {0, 1, 3, 1, 4, UINT64_C(0x29e493479f20d661), "key", "0:0;"}, {0, 1, 4, 1, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=s/q=s/5:0s=t;};];"}, {0, 1, 5, 1, 6, UINT64_C(0x231a8cd446ee0ac9), "key", "6:0a0[missing];"}, {0, 1, 6, 1, 7, UINT64_C(0x942845b4867ca51b), "key", "6:0a0[];"}, {0, 1, 7, 1, 8, UINT64_C(0x3d1384c085cc7f49), "key", "6:0a1[0:0;];"}, {0, 1, 8, 1, 9, UINT64_C(0x94a9e4235a7c56a3), "key", "6:0a1[0:0;];"}, {0, 1, 9, 1, 10, UINT64_C(0x19057312c1477af1), "key", "6:0a1[0:0;];"}, {0, 1, 10, 1, 11, UINT64_C(0xcbbd21de6c7551fb), "key", "6:0a1[7:0o0{missing};];"}, {0, 1, 11, 1, 12, UINT64_C(0xa7b21ff24b599cc9), "key", "6:0a1[7:0o0{};];"}, {0, 1, 12, 1, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=/q=s/5:0s=t;};];"}, {0, 1, 13, 1, 17, UINT64_C(0x68efa027e7058763), "key", "6:0a1[7:0o1{k=s/q=/5:0s=t;};];"}, {0, 1, 14, 1, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=s/q=/5:0s=t;};];"}, {0, 1, 15, 1, 16, UINT64_C(0x4be45a23fda819b9), "key", "6:0a1[7:0o1{k=s/q=s/0:0;};];"}, {0, 1, 16, 1, 17, UINT64_C(0x9d1ecc2804a38c93), "key", "6:0a1[7:0o1{k=s/q=s/0:0;};];"}, {0, 1, 17, 1, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=s/q=s/5:0s=;};];"}, {0, 1, 18, 0, 18, UINT64_C(0x9ee178ffe1e7da63), "key", "6:0a1[7:0o1{k=s/q=s/5:0s=t;};];"}, {1, 0, 0, 2, 2, UINT64_C(0x08842007b530c95d), "", "0:0;"}, {1, 0, 1, 2, 3, UINT64_C(0xa922fa18e1c37583), "", "0:0;"}, {1, 0, 2, 1, 3, UINT64_C(0xa922fa18e1c37583), "key", "0:0;"}, {1, 0, 3, 1, 4, UINT64_C(0x29e493479f20d661), "key", "0:0;"}, {1, 0, 4, 1, 5, UINT64_C(0x503c4bb364cbb14b), "key", "0:0;"}, {1, 0, 5, 1, 6, UINT64_C(0x2225c4d4461dfe79), "key", "7:0o0{missing};"}, {1, 0, 6, 1, 7, UINT64_C(0x242b85b324f6b6e3), "key", "7:0o0{};"}, {1, 0, 7, 3, 10, UINT64_C(0x154035d1032f5a9b), "key", "7:0o1{k=/q=/0:0;};"}, {1, 0, 8, 2, 10, UINT64_C(0x154035d1032f5a9b), "key", "7:0o1{k=a/q=/0:0;};"}, {1, 0, 9, 2, 11, UINT64_C(0x4b61a128696594d3), "key", "7:0o1{k=a/q=/0:0;};"}, {1, 0, 10, 1, 11, UINT64_C(0x4b61a128696594d3), "key", "7:0o1{k=a/q=a/0:0;};"}, {1, 0, 11, 1, 12, UINT64_C(0x7c79a2ab179bd4f1), "key", "7:0o1{k=a/q=a/0:0;};"}, {1, 0, 12, 2, 14, UINT64_C(0xa516a88d9f1de459), "key", "7:0o1{k=a/q=a/6:0a0[missing];};"}, {1, 0, 13, 1, 14, UINT64_C(0xa516a88d9f1de459), "key", "7:0o1{k=a/q=a/6:0a0[missing];};"}, {1, 0, 14, 1, 15, UINT64_C(0xa364d1a55fcb1e6b), "key", "7:0o1{k=a/q=a/6:0a0[];};"}, {1, 0, 15, 1, 16, UINT64_C(0x6f6e9f01c624a239), "key", "7:0o1{k=a/q=a/6:0a1[0:0;];};"}, {1, 0, 16, 1, 17, UINT64_C(0x7d9a5103b03f7e13), "key", "7:0o1{k=a/q=a/6:0a1[0:0;];};"}, {1, 0, 17, 1, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=a/q=a/6:0a1[5:0s=;];};"}, {1, 0, 18, 0, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=a/q=a/6:0a1[5:0s=t;];};"}, {1, 1, 0, 1, 17, UINT64_C(0xc5a67b07339990bd), "", "7:0o1{k=a/q=a/6:0a1[5:0s=t;];};"}, {1, 1, 1, 1, 18, UINT64_C(0xacb5ba447be336e3), "", "7:0o1{k=a/q=a/6:0a1[5:0s=t;];};"}, {1, 1, 2, 1, 3, UINT64_C(0xa922fa18e1c37583), "key", "0:0;"}, {1, 1, 3, 1, 4, UINT64_C(0x29e493479f20d661), "key", "0:0;"}, {1, 1, 4, 1, 5, UINT64_C(0x503c4bb364cbb14b), "key", "0:0;"}, {1, 1, 5, 1, 6, UINT64_C(0x2225c4d4461dfe79), "key", "7:0o0{missing};"}, {1, 1, 6, 1, 7, UINT64_C(0x242b85b324f6b6e3), "key", "7:0o0{};"}, {1, 1, 7, 1, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=/q=a/6:0a1[5:0s=t;];};"}, {1, 1, 8, 1, 17, UINT64_C(0xe052cbb56cadb10b), "key", "7:0o1{k=a/q=/6:0a1[5:0s=t;];};"}, {1, 1, 9, 1, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=a/q=/6:0a1[5:0s=t;];};"}, {1, 1, 10, 1, 11, UINT64_C(0x4b61a128696594d3), "key", "7:0o1{k=a/q=a/0:0;};"}, {1, 1, 11, 1, 12, UINT64_C(0x7c79a2ab179bd4f1), "key", "7:0o1{k=a/q=a/0:0;};"}, {1, 1, 12, 1, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=a/q=a/6:0a1[5:0s=t;];};"}, {1, 1, 13, 1, 14, UINT64_C(0xa516a88d9f1de459), "key", "7:0o1{k=a/q=a/6:0a0[missing];};"}, {1, 1, 14, 1, 15, UINT64_C(0xa364d1a55fcb1e6b), "key", "7:0o1{k=a/q=a/6:0a0[];};"}, {1, 1, 15, 1, 16, UINT64_C(0x6f6e9f01c624a239), "key", "7:0o1{k=a/q=a/6:0a1[0:0;];};"}, {1, 1, 16, 1, 17, UINT64_C(0x7d9a5103b03f7e13), "key", "7:0o1{k=a/q=a/6:0a1[0:0;];};"}, {1, 1, 17, 1, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=a/q=a/6:0a1[5:0s=;];};"}, {1, 1, 18, 0, 18, UINT64_C(0xacb5ba447be336e3), "key", "7:0o1{k=a/q=a/6:0a1[5:0s=t;];};"}, }; static void CheckCollectionCopies(LegacyTrace& trace, Context& context) { const auto guestBaseline = trace.guestGenerations, heapBaseline = trace.heapGenerations; for (const auto& test : CollectionCases) for (unsigned alias = 0; alias < 2; ++alias) { Value source{}; ParseLegacy(source, test.source ? R"({"a":["t"]})" : R"([{"s":"t"}])"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0, "Register nested legacy Pair source recovery"); std::vector sourceAllocations; for (const auto& [pointer, generation] : trace.guestGenerations) { if (guestBaseline.contains(pointer)) continue; const auto* bytes = reinterpret_cast(pointer); sourceAllocations.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } const LegacyNode* sourceNode = nullptr; for (const auto& [pointer, size] : trace.heap) { const auto* node = reinterpret_cast(pointer); if (!node->nil && node->key == &source) sourceNode = node; } Require(sourceNode != nullptr, "Nested Pair copies require the actual source callback record"); const auto sourceGeneration = trace.heapGenerations.at(const_cast(sourceNode)); const Value sourceValue = source; String key{}; _ZN3sce4Json6StringC1EPKc(&key, "key"); Pair pair; std::memset(&pair, 0xa5, sizeof(pair)); const auto requests = trace.requests.size(); const auto notices = trace.notifications; trace.budget = test.budget; trace.once = test.once; if (alias) _ZN3sce4Json6Object4PairC2ERKNS0_6StringERKNS0_5ValueE(&pair, &key, &source); else _ZN3sce4Json6Object4PairC1ERKNS0_6StringERKNS0_5ValueE(&pair, &key, &source); trace.budget = -1; trace.once = false; std::uint64_t requestOrder = UINT64_C(14695981039346656037); for (auto i = requests; i < trace.requests.size(); ++i) { requestOrder ^= trace.requests[i]; requestOrder *= UINT64_C(1099511628211); } Require(trace.notifications == notices + test.notifications && trace.requests.size() == requests + test.requests && requestOrder == test.requestOrder, "Nested legacy Pair failures must preserve every request, notification and allocation-order fingerprint"); Require(pair.reserved == UINT64_C(0xa5a5a5a5a5a5a5a5) && pair.value.reserved == UINT32_C(0xa5a5a5a5) && !pair.value.auxiliary && std::strcmp(_ZNK3sce4Json6String5c_strEv(&pair.key), test.key) == 0, "Nested legacy copies must preserve inactive bytes, independent metadata and partial key admission"); std::string shape; std::vector values; CollectionShape(pair.value, nullptr, shape, values); Require(shape == test.shape, "Nested legacy copies must preserve partial counts, missing sentinels, both object keys, scalar/string contents and child parent identities"); CheckMap(trace, {{&source, &context}, {&pair.value, &context}}); const auto calls = context.calls; Require(_ZNK3sce4Json5Value10getBooleanEv(&pair.value) == reinterpret_cast(&context.replacement.payload) && context.calls == calls + 1 && context.source == &pair.value && !context.parent, "Even an incomplete nested Pair must retain its independently copied callback and borrowed result identity"); for (const auto* value : values) { if (value == &pair.value) continue; Require(!value->parent && !value->auxiliary && !*_ZNK3sce4Json5Value10getBooleanEv(value) && context.calls == calls + 1, "Unbound legacy descendants must use typed defaults without inheriting the copied root callback"); } if (alias) _ZN3sce4Json6Object4PairD2Ev(&pair); else _ZN3sce4Json6Object4PairD1Ev(&pair); CheckMap(trace, {{&source, &context}}); Require(std::memcmp(&source, &sourceValue, sizeof(source)) == 0 && trace.heapGenerations.at(const_cast(sourceNode)) == sourceGeneration && sourceNode->callback == RecoverLegacy && sourceNode->context == &context, "Nested Pair teardown must preserve the source Value and callback-record generation"); for (const auto& snapshot : sourceAllocations) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Nested Pair failure and cleanup must preserve all source allocation generations and bytes"); Require(_ZNK3sce4Json5Value10getBooleanEv(&source) == reinterpret_cast(&context.replacement.payload) && context.source == &source && !context.parent, "Nested source recovery must remain usable after copied storage is destroyed"); _ZN3sce4Json6StringD1Ev(&key); _ZN3sce4Json5ValueD1Ev(&source); CheckMap(trace, {}); Require(trace.guestGenerations == guestBaseline && trace.heapGenerations == heapBaseline, "Nested legacy copies must restore every original generation in both allocation domains"); } } struct MapReadContext { LegacyTrace* trace; Value* target; Value* copy; Context* replacement; unsigned mode; unsigned reads = 0; int registration = -1; Pair* pair = nullptr; const String* key = nullptr; unsigned alias = 0; }; static void UpdateInheritedMap(void* data) { auto& context = *static_cast(data); context.registration = _ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(context.target, RecoverLegacy, context.replacement); if (context.pair) { if (context.alias == 1) _ZN3sce4Json6Object4PairC1ERKNS0_6StringERKNS0_5ValueE(context.pair, context.key, context.target); else _ZN3sce4Json6Object4PairC2ERKNS0_6StringERKNS0_5ValueE(context.pair, context.key, context.target); } else _ZN3sce4Json5ValueC1ERKS1_(context.copy, context.target); } static int APS5_VABI ReadInheritedMap(char& character, void* data) { auto& context = *static_cast(data); if (!context.reads) { if (context.mode) { if (context.mode == 2) { context.trace->onNotify = UpdateInheritedMap; context.trace->noticeContext = &context; } context.trace->budget = 0; context.trace->once = true; Require(!_ZN3sce4Json6MallocEm(8),"Inherited map testing must reject the actual guest allocation"); context.trace->budget = -1; context.trace->once = false; } if (context.mode != 2) UpdateInheritedMap(&context); } if (context.reads >= 4) return static_cast(0x80848101); character = "true"[context.reads++]; return 0; } static void CheckInheritedMap(LegacyTrace& trace, Context& first, Context& second) { const auto guestBaseline = trace.guestGenerations, heapBaseline = trace.heapGenerations; for (unsigned shape = 0; shape < 3; ++shape) for (bool existing : {false, true}) for (unsigned mode = 0; mode < 3; ++mode) for (unsigned alias = 0; alias < 3; ++alias) { Value target{}, scalarCopy{}, outer{}; Pair pair; std::memset(&pair, 0xa5, sizeof(pair)); Value& copy = alias ? pair.value : scalarCopy; String key{}; if (alias) _ZN3sce4Json6StringC1EPKc(&key, "key"); ParseLegacy(target, shape == 0 ? "9" : shape == 1 ? "[{\"s\":\"text\"}]" : "{\"a\":[\"text\"]}"); if (existing) Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&target, RecoverLegacy, &first) == 0, "Prepare an existing legacy mismatch record before inherited failure"); std::vector targetAllocations; for (const auto& [pointer, generation] : trace.guestGenerations) { if (guestBaseline.contains(pointer)) continue; const auto* bytes = reinterpret_cast(pointer); targetAllocations.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } const Value targetValue = target; _ZN3sce4Json5ValueC1Ev(&outer); MapReadContext context{&trace, &target, ©, &second, mode}; if (alias) { context.pair = &pair; context.key = &key; context.alias = alias; } const auto requests = trace.requests.size(); const auto notices = trace.notifications; const int status = _ZN3sce4Json6Parser5parseERNS0_5ValueEPFiRcPvES5_(&outer, ReadInheritedMap, &context); const auto error = static_cast(0x80848102); Require(status == (mode ? error : 0) && context.registration == (mode == 1 ? error : 0) && context.reads == 4 && outer.type == 1 && (outer.payload & 0xff) == 1 && outer.auxiliary, "Legacy map updates must observe failure only after notifier return without clearing the outer parser error or interrupting its admitted literal"); auto expected = mode ? std::vector{8} : std::vector{}; if (alias) { expected.push_back(24); expected.push_back(4); } if (shape) { const auto payload = shape == 1 ? std::vector{8, 24, 48, 48, 48, 8, 24, 104, 104, 104, 2, 24, 2, 8, 24, 5} : std::vector{8, 24, 104, 104, 104, 2, 24, 2, 8, 24, 48, 48, 48, 8, 24, 5}; for (auto bytes : payload) expected.push_back(bytes); } expected.push_back(24); expected.push_back(32); if (alias) Require(pair.reserved == UINT64_C(0xa5a5a5a5a5a5a5a5) && pair.key.text != key.text && std::strcmp(_ZNK3sce4Json6String5c_strEv(&pair.key), "key") == 0, "Inherited failure must preserve independent Pair key ownership, complete key contents and inactive padding"); Require(std::vector(trace.requests.begin() + requests, trace.requests.end()) == expected && trace.notifications == notices + unsigned(mode != 0) && !trace.onNotify, "Inherited map registration must preserve actual failure, root-admission and notifier ordering"); Context* targetContext = mode == 1 ? existing ? &first : nullptr : &second; Context* copyContext = mode == 1 ? nullptr : &second; CheckMap(trace, {{&target, targetContext}, {©, copyContext}}); Require(!copy.parent && !copy.auxiliary && copy.type == (shape ? shape == 1 ? 6 : 7 : 3) && (shape || copy.payload == 9) && std::memcmp(&target, &targetValue, sizeof(target)) == 0, "Inherited callback-map failure must preserve copied payload type and source ownership metadata"); const auto verifyShape = [&] { std::string actual; std::vector values; CollectionShape(copy, nullptr, actual, values); const char* expectedShape = shape == 0 ? "3:0=9;" : shape == 1 ? "6:0a1[7:0o1{k=s/q=s/5:0s=text;};];" : "7:0o1{k=a/q=a/6:0a1[5:0s=text;];};"; Require(actual == expectedShape, "Inherited copies must preserve complete nested payloads, independent internal/public keys and unbound descendant parents"); }; verifyShape(); const auto verifyRecovery = [&](const Value& value, Context* expectedContext) { const auto firstCalls = first.calls, secondCalls = second.calls; const auto* result = _ZNK3sce4Json5Value10getBooleanEv(&value); if (expectedContext) Require(result == reinterpret_cast(&expectedContext->replacement.payload) && expectedContext->source == &value && !expectedContext->parent && expectedContext->calls == (expectedContext == &first ? firstCalls : secondCalls) + 1, "Admitted legacy records must retain their exact callback context, receiver and borrowed result"); else Require(!*result && first.calls == firstCalls && second.calls == secondCalls, "An empty map entry retained after inherited failure must use the typed default without callback dispatch"); }; verifyRecovery(target, targetContext); verifyRecovery(copy, copyContext); const auto guest = trace.guestGenerations, heap = trace.heapGenerations; const auto beforeRetry = trace.requests.size(); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&target, RecoverLegacy, &second) == 0 && _ZN3sce4Json5ValueaSERKS1_(©, &target) == ©, "Independent registration and copy retry must succeed after the outer failure scope completes"); Require((shape ? trace.guestGenerations.size() == guest.size() && trace.requests.size() > beforeRetry : trace.guestGenerations == guest && trace.requests.size() == beforeRetry) && trace.heapGenerations == heap, "Retry must reuse legacy callback records and retain balanced payload ownership across collection replacement"); verifyShape(); CheckMap(trace, {{&target, &second}, {©, &second}}); verifyRecovery(target, &second); verifyRecovery(copy, &second); for (const auto& snapshot : targetAllocations) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Inherited failure, registration retry and copying must preserve the original source auxiliary and fallback generations"); Require(_ZN3sce4Json6Parser5parseERNS0_5ValueEPKcm(&outer, "false", 5) == 0 && outer.type == 1 && !(outer.payload & 0xff), "The next independent parse must not inherit an already completed callback-map failure"); if (alias) { if (alias == 1) _ZN3sce4Json6Object4PairD1Ev(&pair); else _ZN3sce4Json6Object4PairD2Ev(&pair); _ZN3sce4Json6StringD1Ev(&key); } else _ZN3sce4Json5ValueD1Ev(©); _ZN3sce4Json5ValueD1Ev(&target); _ZN3sce4Json5ValueD1Ev(&outer); CheckMap(trace, {}); Require(trace.guestGenerations == guestBaseline && trace.heapGenerations == heapBaseline, "Inherited map updates and retries must reclaim every temporary generation in both allocator domains"); } } static int CheckHeapExceptions(unsigned budget) { Require(budget <= 2, "Heap exceptions must cover sentinel, entry and complete admission"); LegacyTrace trace; HeapTrace = &trace; LegacyAllocator allocator; Parameter parameter{&allocator, &trace, 16384}; std::uint8_t owner = 0; _ZN3sce4Json11InitializerC1Ev(&owner); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0, "Initialize legacy heap exception resources"); Context context; _ZN3sce4Json5ValueC1Eb(&context.replacement, true); Value source{}; ParseLegacy(source); const Value sourceValue = source; const auto baseline = trace.guestGenerations; std::vector snapshots; for (const auto& [pointer, generation] : baseline) { const auto* bytes = reinterpret_cast(pointer); snapshots.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } trace.heapBudget = static_cast(budget); const auto requests = trace.requests.size(); bool caught = false; try { Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0, "Complete registration must succeed"); } catch (const std::bad_alloc&) { caught = true; } Require(caught == (budget < 2) && owner && trace.heap.size() == budget && trace.guest.size() == baseline.size() + 1 && trace.requests.size() == requests + 1 && trace.requests.back() == 24 && !trace.notifications, "Libc exceptions must propagate without guest OOM notifications or reclaiming the admitted map header"); void* header = nullptr; for (const auto& [pointer, generation] : trace.guestGenerations) if (!baseline.contains(pointer)) { Require(!header, "Admission creates only one guest map header"); header = pointer; } Require(header && trace.guest.at(header) == 24, "The unpublished header must remain owned in its guest allocator domain"); const auto headerGeneration = trace.guestGenerations.at(header); if (!budget) { std::array expected; expected.fill(0xa5); std::memset(expected.data() + 8, 0, 8); Require(std::memcmp(header, expected.data(), expected.size()) == 0 && trace.heap.empty(), "Sentinel failure must leave only the count initialized in the unpublished header"); } else CheckMap(trace, budget == 1 ? std::map{} : std::map{{&source, &context}}); trace.heapBudget = -1; const auto retryRequests = trace.requests.size(); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0 && trace.requests.size() == retryRequests + unsigned(!budget) && trace.heap.size() == 2 && trace.guestGenerations.at(header) == headerGeneration, "Retry must replace only an unpublished map and reuse an already published sentinel"); CheckMap(trace, {{&source, &context}}); const auto calls = context.calls; Require(_ZNK3sce4Json5Value10getBooleanEv(&source) == reinterpret_cast(&context.replacement.payload) && context.calls == calls + 1 && context.source == &source && !context.parent, "Retried callback metadata must dispatch the original context and borrowed result"); Require(std::memcmp(&source, &sourceValue, sizeof(source)) == 0, "Heap failure and retry must preserve source metadata ownership"); for (const auto& snapshot : snapshots) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Heap failure must preserve preexisting allocation bytes and generations"); _ZN3sce4Json5ValueD1Ev(&source); _ZN3sce4Json5ValueD1Ev(&context.replacement); Require(_ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && !owner && trace.heap.empty() && trace.heapGenerations.empty() && trace.guest.size() == unsigned(!budget), "Termination must reclaim published map storage while preserving the orphaned unpublished header"); if (!budget) { Require(trace.guestGenerations.at(header) == headerGeneration, "Library cleanup must not falsely claim orphan reclamation"); FreeLegacy(nullptr, header, &trace); } Require(trace.guest.empty() && trace.guestGenerations.empty(), "The fixture separately reclaims any orphaned allocation"); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0 && _ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && !owner && trace.guest.empty() && trace.heap.empty(), "Heap exception cleanup must permit a fresh module generation"); HeapTrace = nullptr; return 0; } static int CheckCopyHeapExceptions(unsigned shape, unsigned alias) { Require(shape < 4 && alias < 3, "Heap-copy schedules cover scalar, string, nested collections and constructor aliases"); LegacyTrace trace; HeapTrace = &trace; LegacyAllocator allocator; Parameter parameter{&allocator, &trace, 16384}; std::uint8_t owner = 0; _ZN3sce4Json11InitializerC1Ev(&owner); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0, "Initialize copy exception resources"); Context context; _ZN3sce4Json5ValueC1Eb(&context.replacement, true); Value source{}; ParseLegacy(source, shape == 0 ? "9" : shape == 1 ? "\"text\"" : shape == 2 ? "[{\"s\":\"text\"}]" : "{\"a\":[\"text\"]}"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0, "Prepare source callback ownership"); String key{}; _ZN3sce4Json6StringC1EPKc(&key, "key"); Pair pair; std::memset(&pair, 0xa5, sizeof(pair)); Value scalar{}; Value& copy = alias ? pair.value : scalar; const Value sourceValue = source; const auto baseline = trace.guestGenerations, heapBaseline = trace.heapGenerations; std::vector snapshots; for (const auto& [pointer, generation] : baseline) { if (trace.guest.at(pointer) == 24 && trace.heap.contains(*reinterpret_cast(pointer))) continue; const auto* bytes = reinterpret_cast(pointer); snapshots.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } const auto requests = trace.requests.size(); trace.heapBudget = 0; bool caught = false; try { if (!alias) _ZN3sce4Json5ValueC1ERKS1_(©, &source); else if (alias == 1) _ZN3sce4Json6Object4PairC1ERKNS0_6StringERKNS0_5ValueE(&pair, &key, &source); else _ZN3sce4Json6Object4PairC2ERKNS0_6StringERKNS0_5ValueE(&pair, &key, &source); } catch (const std::bad_alloc&) { caught = true; } std::vector expected; if (alias) expected = {24, 4}; const auto payload = shape == 0 ? std::vector{} : shape == 1 ? std::vector{8, 24, 5} : shape == 2 ? std::vector{8, 24, 48, 48, 48, 8, 24, 104, 104, 104, 2, 24, 2, 8, 24, 5} : std::vector{8, 24, 104, 104, 104, 2, 24, 2, 8, 24, 48, 48, 48, 8, 24, 5}; expected.insert(expected.end(), payload.begin(), payload.end()); const unsigned retained = shape == 0 ? 0 : shape == 1 ? 3 : 14; Require(caught && owner && !trace.notifications && trace.heapGenerations == heapBaseline && trace.guest.size() == baseline.size() + retained + unsigned(alias != 0) * 2 && std::vector(trace.requests.begin() + requests, trace.requests.end()) == expected, "Map-entry exceptions must preserve completed copy allocations without constructor rollback or guest OOM notices"); CheckMap(trace, {{&source, &context}}); const auto verifyPayload = [&] { std::string actual; std::vector values; CollectionShape(copy, nullptr, actual, values); const char* expectedShape = shape == 0 ? "3:0=9;" : shape == 1 ? "5:0s=text;" : shape == 2 ? "6:0a1[7:0o1{k=s/q=s/5:0s=text;};];" : "7:0o1{k=a/q=a/6:0a1[5:0s=text;];};"; Require(actual == expectedShape && !copy.auxiliary, "Heap exceptions must preserve complete payloads and independent callback metadata"); if (alias) Require(pair.key.text != key.text && std::strcmp(_ZNK3sce4Json6String5c_strEv(&pair.key), "key") == 0 && pair.reserved == UINT64_C(0xa5a5a5a5a5a5a5a5), "Failed Pair constructors must retain their independent key and inactive padding"); }; verifyPayload(); const auto calls = context.calls; Require(!*_ZNK3sce4Json5Value10getBooleanEv(©) && context.calls == calls, "An unpublished copy callback must use the typed default"); Require(_ZNK3sce4Json5Value10getBooleanEv(&source) == reinterpret_cast(&context.replacement.payload) && context.calls == calls + 1 && context.source == &source, "Copy failure must preserve the source callback and borrowed result"); trace.heapBudget = -1; Require(_ZN3sce4Json5ValueaSERKS1_(©, &source) == ©, "Assignment retry must publish the copied callback"); CheckMap(trace, {{&source, &context}, {©, &context}}); verifyPayload(); Require(_ZNK3sce4Json5Value10getBooleanEv(©) == reinterpret_cast(&context.replacement.payload) && context.source == © && !context.parent, "Retried copies must recover through their own callback identity"); Require(std::memcmp(&source, &sourceValue, sizeof(source)) == 0, "Copy failure and retry must preserve source Value bytes"); for (const auto& [pointer, generation] : baseline) Require(trace.guestGenerations.at(pointer) == generation, "Retry must preserve every preexisting allocation generation including shared map storage"); for (const auto& snapshot : snapshots) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Copy failure must preserve all preexisting allocation bytes and generations"); if (!alias) _ZN3sce4Json5ValueD1Ev(©); else if (alias == 1) _ZN3sce4Json6Object4PairD1Ev(&pair); else _ZN3sce4Json6Object4PairD2Ev(&pair); _ZN3sce4Json6StringD1Ev(&key); _ZN3sce4Json5ValueD1Ev(&source); _ZN3sce4Json5ValueD1Ev(&context.replacement); Require(_ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && !owner && trace.guest.empty() && trace.heap.empty() && trace.guestGenerations.empty() && trace.heapGenerations.empty(), "Failed construction, retry and explicit destruction must reclaim both allocator domains"); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0 && _ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && trace.guest.empty() && trace.heap.empty(), "Copy exceptions must permit a fresh module generation"); HeapTrace = nullptr; return 0; } static int CheckArrayHeapExceptions(unsigned budget, unsigned alias, bool wrapped = false) { Require(budget <= 2 && alias < 2, "Array-copy schedules cover both child entries and constructor aliases"); LegacyTrace trace; HeapTrace = &trace; LegacyAllocator allocator; Parameter parameter{&allocator, &trace, 16384}; std::uint8_t owner = 0; _ZN3sce4Json11InitializerC1Ev(&owner); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0, "Initialize array-copy exception resources"); Context context; _ZN3sce4Json5ValueC1Eb(&context.replacement, true); Value source{}; ParseLegacy(source); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0, "Prepare copied child callbacks"); Array array{}; _ZN3sce4Json5ArrayC1Ev(&array); _ZN3sce4Json5Array9push_backERKNS0_5ValueE(&array, &source); _ZN3sce4Json5Array9push_backERKNS0_5ValueE(&array, &source); auto* sourceHeader = reinterpret_cast(array.items); std::map entries{{&source, &context}}; for (auto* node = sourceHeader->head->next; node != sourceHeader->head; node = node->next) entries.emplace(&node->value, &context); CheckMap(trace, entries); const auto baseline = trace.guestGenerations, heapBaseline = trace.heapGenerations; const Value sourceValue = source; std::vector snapshots; for (const auto& [pointer, generation] : baseline) { if (trace.guest.at(pointer) == 24 && trace.heap.contains(*reinterpret_cast(pointer))) continue; const auto* bytes = reinterpret_cast(pointer); snapshots.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } Array directCopy; std::memset(&directCopy, 0xa5, sizeof(directCopy)); Value wrappedCopy; std::memset(&wrappedCopy, 0xa5, sizeof(wrappedCopy)); const auto requests = trace.requests.size(); trace.heapBudget = static_cast(budget); bool caught = false; try { if (wrapped) { if (alias) _ZN3sce4Json5ValueC2ERKNS0_5ArrayE(&wrappedCopy, &array); else _ZN3sce4Json5ValueC1ERKNS0_5ArrayE(&wrappedCopy, &array); } else if (alias) _ZN3sce4Json5ArrayC2ERKS1_(&directCopy, &array); else _ZN3sce4Json5ArrayC1ERKS1_(&directCopy, &array); } catch (const std::bad_alloc&) { caught = true; } if (wrapped) Require(wrappedCopy.type == 6 && !wrappedCopy.parent && !wrappedCopy.auxiliary && trace.guest.contains(reinterpret_cast(wrappedCopy.payload)), "Value wrappers must publish their independent Array handle and type before callback entry failure"); Array& copy = wrapped ? *reinterpret_cast(wrappedCopy.payload) : directCopy; std::vector expected{24, 48, 48, 48}; if (wrapped) expected.insert(expected.begin(), 8); if (budget) expected.push_back(48); Require(caught == (budget < 2) && trace.guest.contains(copy.items) && trace.guest.size() == baseline.size() + (budget == 1 ? 5u : 4u) + unsigned(wrapped) && trace.heap.size() == heapBaseline.size() + budget && !trace.notifications && std::vector(trace.requests.begin() + requests, trace.requests.end()) == expected, "Interrupted Array construction must publish empty destination storage and retain the temporary list without rollback"); auto* copyHeader = reinterpret_cast(copy.items); Require(copyHeader->count == (caught ? 0u : 2u) && copyHeader->head && (caught ? copyHeader->head->next == copyHeader->head && copyHeader->head->previous == copyHeader->head : true), "Only completed list copying may replace the initial empty destination"); std::map orphans; if (caught) for (const auto& [pointer, generation] : trace.guestGenerations) { if (!baseline.contains(pointer) && pointer != copy.items && pointer != copyHeader->head && (!wrapped || pointer != reinterpret_cast(wrappedCopy.payload))) { Require(trace.guest.at(pointer) == 48, "Only temporary list links become orphaned"); orphans.emplace(pointer, generation); } } Require(orphans.size() == (caught ? budget + 2 : 0), "Failed copies retain the temporary sentinel and admitted child nodes"); for (const auto& [pointer, generation] : trace.heapGenerations) if (!heapBaseline.contains(pointer)) { const auto* node = reinterpret_cast(pointer); Require(!node->nil && node->callback == RecoverLegacy && node->context == &context && node->key->type == 3 && node->key->payload == 9, "Completed child callback records must remain independently published even in the orphaned temporary list"); entries.emplace(node->key, &context); } CheckMap(trace, entries); trace.heapBudget = -1; Require(_ZN3sce4Json5ArrayaSERKS1_(©, &array) == © && _ZNK3sce4Json5Array4sizeEv(©) == 2, "Assignment retry must replace the retained empty destination"); for (const auto& [pointer, generation] : orphans) Require(trace.guestGenerations.at(pointer) == generation, "Retry must not claim orphaned temporary-list ownership"); for (const auto& snapshot : snapshots) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Interrupted copy and retry must preserve source storage bytes and generations"); Require(std::memcmp(&source, &sourceValue, sizeof(source)) == 0, "Original callback source metadata must remain unchanged"); const auto* child = _ZNK3sce4Json5Array5frontEv(©); Require(_ZNK3sce4Json5Value10getBooleanEv(child) == reinterpret_cast(&context.replacement.payload) && context.source == child && !context.parent, "Retried children must dispatch through their own callback records"); if (wrapped) _ZN3sce4Json5ValueD1Ev(&wrappedCopy); else _ZN3sce4Json5ArrayD1Ev(©); _ZN3sce4Json5ArrayD1Ev(&array); _ZN3sce4Json5ValueD1Ev(&source); _ZN3sce4Json5ValueD1Ev(&context.replacement); Require(_ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && !owner && trace.heap.empty() && trace.heapGenerations.empty() && trace.guestGenerations == orphans, "Module teardown reclaims callback records but cannot reclaim orphaned caller list nodes"); for (const auto& [pointer, generation] : orphans) FreeLegacy(nullptr, pointer, &trace); Require(trace.guest.empty() && _ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0 && _ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && trace.guest.empty() && trace.heap.empty(), "Separate fixture reclamation must leave fresh module initialization usable"); HeapTrace = nullptr; return 0; } static int CheckObjectHeapExceptions(unsigned budget, unsigned alias, bool wrapped) { Require(budget <= 2 && alias < 2, "Object-copy schedules cover both child entries and constructor aliases"); LegacyTrace trace; HeapTrace = &trace; LegacyAllocator allocator; Parameter parameter{&allocator, &trace, 16384}; std::uint8_t owner = 0; _ZN3sce4Json11InitializerC1Ev(&owner); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0, "Initialize tree-copy exception resources"); Context context; _ZN3sce4Json5ValueC1Eb(&context.replacement, true); Value source{}, root{}; ParseLegacy(source); ParseLegacy(root, "{\"a\":9,\"b\":9}"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &context) == 0, "Prepare source callback records"); auto* object = reinterpret_cast(root.payload); auto* sourceHeader = reinterpret_cast(object->items); std::string ignored; std::vector values; CollectionTreeShape(sourceHeader->head->parent, &root, ignored, values); std::map entries{{&source, &context}}; for (const auto* value : values) { _ZN3sce4Json5ValueaSERKS1_(const_cast(value), &source); entries.emplace(value, &context); } CheckMap(trace, entries); const auto baseline = trace.guestGenerations, heapBaseline = trace.heapGenerations; const Value sourceValue = source, rootValue = root; std::vector snapshots; for (const auto& [pointer, generation] : baseline) { if (trace.guest.at(pointer) == 24 && trace.heap.contains(*reinterpret_cast(pointer))) continue; const auto* bytes = reinterpret_cast(pointer); snapshots.push_back({pointer, generation, {bytes, bytes + trace.guest.at(pointer)}}); } Object direct; std::memset(&direct, 0xa5, sizeof(direct)); Value value; std::memset(&value, 0xa5, sizeof(value)); const auto requests = trace.requests.size(); trace.heapBudget = static_cast(budget); bool caught = false; try { if (wrapped) { if (alias) _ZN3sce4Json5ValueC2ERKNS0_6ObjectE(&value, object); else _ZN3sce4Json5ValueC1ERKNS0_6ObjectE(&value, object); } else if (alias) _ZN3sce4Json6ObjectC2ERKS1_(&direct, object); else _ZN3sce4Json6ObjectC1ERKS1_(&direct, object); } catch (const std::bad_alloc&) { caught = true; } if (wrapped) Require(value.type == 7 && !value.parent && !value.auxiliary && trace.guest.contains(reinterpret_cast(value.payload)), "Value constructors must retain the published Object type and independent handle"); Object& copy = wrapped ? *reinterpret_cast(value.payload) : direct; std::vector expected{24, 104, 104, 104, 2, 24, 2}; if (budget) expected.insert(expected.end(), {104, 2, 24, 2}); if (wrapped) expected.insert(expected.begin(), 8); Require(caught == (budget < 2) && trace.guest.contains(copy.items) && trace.guest.size() == baseline.size() + (budget == 0 ? 7u : budget == 1 ? 11u : 10u) + unsigned(wrapped) && trace.heap.size() == heapBaseline.size() + budget && !trace.notifications && std::vector(trace.requests.begin() + requests, trace.requests.end()) == expected, "Interrupted tree construction must retain the published empty destination and unfinished replacement tree without rollback"); auto* header = reinterpret_cast(copy.items); Require(header->count == (caught ? 0u : 2u) && header->head && (!caught || header->head->parent == header->head), "Only complete tree copying may publish the replacement root"); std::map orphans; if (caught) for (const auto& [pointer, generation] : trace.guestGenerations) { if (!baseline.contains(pointer) && pointer != copy.items && pointer != header->head && (!wrapped || pointer != reinterpret_cast(value.payload))) orphans.emplace(pointer, generation); } Require(orphans.size() == (caught ? budget == 0 ? 5u : 9u : 0u), "Unfinished trees retain their sentinel, nodes and independently allocated internal/public keys"); for (const auto& [pointer, generation] : trace.heapGenerations) if (!heapBaseline.contains(pointer)) { const auto* node = reinterpret_cast(pointer); Require(!node->nil && node->callback == RecoverLegacy && node->context == &context && node->key->type == 3 && node->key->payload == 9, "Completed replacement-tree child records remain published after the next entry allocation fails"); entries.emplace(node->key, &context); } CheckMap(trace, entries); trace.heapBudget = -1; Require(_ZN3sce4Json6ObjectaSERKS1_(©, object) == ©, "Independent assignment retry must publish a complete tree"); Value view{nullptr, nullptr, reinterpret_cast(©), 0, TypeObject}; std::string actual; std::vector copiedValues; CollectionShape(view, nullptr, actual, copiedValues); Require(actual == "7:0o2{k=a/q=a/3:0=9;k=b/q=b/3:0=9;};", "Retried trees must preserve both keys, scalar contents and parent links"); const auto* child = &reinterpret_cast(copy.items)->head->left->pair.value; Require(_ZNK3sce4Json5Value10getBooleanEv(child) == reinterpret_cast(&context.replacement.payload) && context.source == child && !context.parent, "Retried tree entries must dispatch through their own callback records"); for (const auto& [pointer, generation] : orphans) Require(trace.guestGenerations.at(pointer) == generation, "Retry must not reclaim the orphaned replacement tree"); for (const auto& snapshot : snapshots) Require(trace.guestGenerations.at(snapshot.pointer) == snapshot.generation && std::memcmp(snapshot.pointer, snapshot.bytes.data(), snapshot.bytes.size()) == 0, "Failed tree copies and retry must preserve every original allocation and source byte"); Require(std::memcmp(&source, &sourceValue, sizeof(source)) == 0 && std::memcmp(&root, &rootValue, sizeof(root)) == 0, "Both original Values must retain their metadata ownership"); if (wrapped) _ZN3sce4Json5ValueD1Ev(&value); else _ZN3sce4Json6ObjectD1Ev(©); _ZN3sce4Json5ValueD1Ev(&root); _ZN3sce4Json5ValueD1Ev(&source); _ZN3sce4Json5ValueD1Ev(&context.replacement); Require(_ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && !owner && trace.heap.empty() && trace.heapGenerations.empty() && trace.guestGenerations == orphans, "Module teardown reclaims all callback records while leaving the orphaned caller tree intact"); for (const auto& [pointer, generation] : orphans) FreeLegacy(nullptr, pointer, &trace); Require(trace.guest.empty() && _ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&owner, ¶meter) == 0 && _ZN3sce4Json11Initializer9terminateEv(&owner) == 0 && trace.guest.empty() && trace.heap.empty(), "Separate orphan reclamation must preserve fresh module initialization and cleanup"); HeapTrace = nullptr; return 0; } int main(int argc, char** argv) { if (argc == 5 && std::strcmp(argv[1], "object-heap") == 0) return CheckObjectHeapExceptions(static_cast(std::strtoul(argv[2], nullptr, 10)), static_cast(std::strtoul(argv[3], nullptr, 10)), std::strcmp(argv[4], "wrapped") == 0); if (argc == 4 && std::strcmp(argv[1], "value-array-heap") == 0) return CheckArrayHeapExceptions(static_cast(std::strtoul(argv[2], nullptr, 10)), static_cast(std::strtoul(argv[3], nullptr, 10)), true); if (argc == 4 && std::strcmp(argv[1], "array-heap") == 0) return CheckArrayHeapExceptions(static_cast(std::strtoul(argv[2], nullptr, 10)), static_cast(std::strtoul(argv[3], nullptr, 10))); if (argc == 3) return CheckCopyHeapExceptions(static_cast(std::strtoul(argv[1], nullptr, 10)), static_cast(std::strtoul(argv[2], nullptr, 10))); if (argc == 2) return CheckHeapExceptions(static_cast(std::strtoul(argv[1], nullptr, 10))); LegacyTrace trace; HeapTrace = &trace; LegacyAllocator allocator; Parameter parameter{&allocator, &trace, 16384}; std::uint8_t initializer = 0; _ZN3sce4Json11InitializerC1Ev(&initializer); Require(_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(&initializer, ¶meter) == 0 && trace.guest.size() == 11, "Initialize legacy allocation and shared mutex resources"); const auto baseline = trace.guest.size(); Context first, second; _ZN3sce4Json5ValueC1Eb(&first.replacement, true); _ZN3sce4Json5ValueC1Eb(&second.replacement, false); Value source{}; _ZN3sce4Json5ValueC1El(&source, 9); Require(static_cast(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &first)) == 0x80848104 && trace.guest.size() == baseline && trace.heap.empty(), "Legacy mismatch registration must reject a root without auxiliary metadata"); _ZN3sce4Json5ValueD1Ev(&source); ParseLegacy(source); const auto before = trace.guest.size(); trace.budget = 0; Require(static_cast(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &first)) == 0x80848102 && trace.notifications == 1 && trace.guest.size() == before && trace.heap.empty(), "Failed map admission must retain the root and permit retry"); trace.budget = -1; Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &first) == 0, "Register legacy mismatch after failure"); CheckMap(trace, {{&source, &first}}); Require(*_ZNK3sce4Json5Value10getBooleanEv(&source) && first.source == &source && !first.parent, "Legacy getters must dispatch the registered borrowed replacement"); const auto guest = trace.guest.size(); const auto heap = trace.heap.size(); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &second) == 0 && !_ZNK3sce4Json5ValuecvbEv(&source) && second.calls == 1 && trace.guest.size() == guest && trace.heap.size() == heap, "Legacy callback replacement must reuse the map entry and govern boolean conversion"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, nullptr, nullptr) == 0 && !*_ZNK3sce4Json5Value10getBooleanEv(&source), "A null legacy mismatch callback must disable dispatch without removing the entry"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&source, RecoverLegacy, &first) == 0, "Restore legacy callback"); Value copy{}; _ZN3sce4Json5ValueC1ERKS1_(©, &source); Require(!copy.auxiliary && *_ZNK3sce4Json5Value10getBooleanEv(©) && first.source == ©, "Legacy value copies must propagate map callbacks independently of auxiliary ownership"); Value assigned{}; ParseLegacy(assigned); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&assigned, RecoverLegacy, &second) == 0, "Prepare legacy assignment callback"); auto* auxiliary = assigned.auxiliary; _ZN3sce4Json5ValueaSERKS1_(&assigned, &source); Require(assigned.auxiliary == auxiliary && *_ZNK3sce4Json5Value10getBooleanEv(&assigned) && first.source == &assigned, "Legacy assignment must copy the source map record while retaining destination metadata"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&assigned, RecoverLegacy, &second) == 0, "Prepare distinct swap callbacks"); _ZN3sce4Json5Value4swapERS1_(&source, &assigned); Require(!*_ZNK3sce4Json5Value10getBooleanEv(&source) && *_ZNK3sce4Json5Value10getBooleanEv(&assigned) && assigned.auxiliary == auxiliary, "Legacy swap must exchange callback records and retain destination auxiliary ownership"); CheckMap(trace, {{&source, &second}, {©, &first}, {&assigned, &first}}); _ZN3sce4Json5Value4swapERS1_(&source, &assigned); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&assigned, RecoverLegacy, &first) == 0, "Restore assignment callback after swap"); Array array{}; _ZN3sce4Json5ArrayC1Ev(&array); _ZN3sce4Json5Array9push_backERKNS0_5ValueE(&array, &source); const auto* element = _ZNK3sce4Json5Array5frontEv(&array); Require(*_ZNK3sce4Json5Value10getBooleanEv(element) && first.source == element && !first.parent, "Legacy array append must copy the handler map entry without binding a modern parent"); CheckMap(trace, {{&source, &first}, {©, &first}, {&assigned, &first}, {element, &first}}); trace.budget = 0; _ZN3sce4Json5Array9push_backERKNS0_5ValueE(&array, &source); trace.budget = -1; Require(_ZNK3sce4Json5Array4sizeEv(&array) == 0, "A failed legacy append must remove the existing tail and its handler record"); CheckMap(trace, {{&source, &first}, {©, &first}, {&assigned, &first}}); _ZN3sce4Json5ArrayD1Ev(&array); Value parsed{}; ParseLegacy(parsed, "[9]"); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&parsed, RecoverLegacy, &first) == 0, "Register legacy parsed-container recovery"); const auto* child = _ZNK3sce4Json5Array5frontEv(reinterpret_cast(parsed.payload)); Require(*_ZNK3sce4Json5Value10getBooleanEv(child) && first.source == child && first.parent == &parsed, "Legacy descendant mismatch recovery must use the root map and immediate parent"); _ZN3sce4Json5ValueD1Ev(&parsed); Value null{}; ParseLegacy(null, "null"); NullContext nullContext{&source, &first}; Require(_ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_(&null, RecoverLegacyNull, &nullContext) == 0 && *_ZNK3sce4Json5Value10getBooleanEv(&null), "Legacy local null recovery must preserve its pre-guard dispatch"); _ZN3sce4Json5ValueD1Ev(&null); _ZN3sce4Json5ValueD1Ev(&assigned); _ZN3sce4Json5ValueD1Ev(©); _ZN3sce4Json5ValueD1Ev(&source); CheckMap(trace, {}); CheckPairCopies(trace, first); CheckCollectionCopies(trace, first); CheckInheritedMap(trace, first, second); std::array roots{}; std::map entries; for (unsigned index = 0; index < roots.size(); ++index) { auto& root = roots[index * 13 % roots.size()]; ParseLegacy(root); Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&root, RecoverLegacy, &first) == 0, "Register legacy tree entry"); entries.emplace(&root, &first); CheckMap(trace, entries); } for (unsigned index = 0; index < roots.size(); ++index) { auto& root = roots[index * 7 % roots.size()]; _ZN3sce4Json5ValueD1Ev(&root); entries.erase(&root); CheckMap(trace, entries); } _ZN3sce4Json5ValueD1Ev(&second.replacement); _ZN3sce4Json5ValueD1Ev(&first.replacement); Require(trace.guest.size() == baseline + 1 && trace.heap.size() == 1, "Empty legacy map storage must remain owned until termination"); Require(_ZN3sce4Json11Initializer9terminateEv(&initializer) == 0 && trace.guest.empty() && trace.heap.empty() && trace.guestGenerations.empty() && trace.heapGenerations.empty(), "Termination must release both allocator domains and all legacy map resources"); HeapTrace = nullptr; return 0; }