From 149d2c3e6d9da3e42586884393ad8e6ec3c04cfe Mon Sep 17 00:00:00 2001 From: vibecode2 Date: Sat, 4 Oct 2025 21:14:18 +0200 Subject: [PATCH 1/4] Clean stack for uninitialized variables inside GetKV3Defaults --- src/main/dumpers/schemas/metadata_stringifier.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/dumpers/schemas/metadata_stringifier.cpp b/src/main/dumpers/schemas/metadata_stringifier.cpp index a6bed79..3ebd1da 100644 --- a/src/main/dumpers/schemas/metadata_stringifier.cpp +++ b/src/main/dumpers/schemas/metadata_stringifier.cpp @@ -69,6 +69,15 @@ namespace Dumpers::Schemas } } + // Any function called after this will have uninitialized variables set to zero + void CleanStack() { + // stack size might need to be increased for larger classes (perhaps use alloca with class size + extra) + volatile char stack[0x10000]; + for(size_t i = 0; i < sizeof(stack); ++i) { + stack[i] = 0; + } + } + // Determine how and if to output metadata entry value based on it's type. std::optional GetMetadataValue(const SchemaMetadataEntryData_t& entry, const char* metadataTargetName) { @@ -135,6 +144,7 @@ namespace Dumpers::Schemas if (!entry.m_pData || !(*(void**)entry.m_pData) || !strcmp(metadataTargetName, "CastSphereSATParams_t")) return "Could not parse KV3 Defaults"; + CleanStack(); // Prepare stack for uninitialized variables in class constructor inside GetKV3Defaults auto value = reinterpret_cast(*(void**)entry.m_pData)(); if (!value) return "Could not parse KV3 Defaults"; @@ -188,4 +198,4 @@ namespace Dumpers::Schemas return {}; } -} // namespace Dumpers::Schemas \ No newline at end of file +} // namespace Dumpers::Schemas From b0c3ab0ffc03a63c116ef5278f8316646c5fb069 Mon Sep 17 00:00:00 2001 From: vibecode2 Date: Sat, 4 Oct 2025 21:30:09 +0200 Subject: [PATCH 2/4] force noinline for CleanStack to work properly --- src/main/dumpers/schemas/metadata_stringifier.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/dumpers/schemas/metadata_stringifier.cpp b/src/main/dumpers/schemas/metadata_stringifier.cpp index 3ebd1da..3112bc0 100644 --- a/src/main/dumpers/schemas/metadata_stringifier.cpp +++ b/src/main/dumpers/schemas/metadata_stringifier.cpp @@ -70,6 +70,11 @@ namespace Dumpers::Schemas } // Any function called after this will have uninitialized variables set to zero +#ifdef WIN32 + __declspec(noinline) +#else + __attribute__((noinline)) +#endif void CleanStack() { // stack size might need to be increased for larger classes (perhaps use alloca with class size + extra) volatile char stack[0x10000]; From 302e8f1d5440135a2b68a859da4b6cd4976a4845 Mon Sep 17 00:00:00 2001 From: vibecode2 Date: Sat, 4 Oct 2025 21:38:28 +0200 Subject: [PATCH 3/4] Normalizing json is no longer needed --- .../dumpers/schemas/metadata_stringifier.cpp | 64 ++----------------- 1 file changed, 7 insertions(+), 57 deletions(-) diff --git a/src/main/dumpers/schemas/metadata_stringifier.cpp b/src/main/dumpers/schemas/metadata_stringifier.cpp index 3112bc0..0e63ce4 100644 --- a/src/main/dumpers/schemas/metadata_stringifier.cpp +++ b/src/main/dumpers/schemas/metadata_stringifier.cpp @@ -30,9 +30,6 @@ #include #include "metadata_stringifier.h" #include -#include "../../vendor/json.hpp" - -using json = nlohmann::ordered_json; class SimpleCUtlString { public: @@ -46,41 +43,18 @@ class SimpleCUtlString { namespace Dumpers::Schemas { - // Recursively replace all primitive values in JSON with their defaults - void NormalizePrimitiveValues(json& j) { - if (j.is_number_integer()) { - j = 0; - } - else if (j.is_number_float()) { - j = 0.0; - } - else if (j.is_boolean()) { - j = false; - } - else if (j.is_array()) { - for (auto& element : j) { - NormalizePrimitiveValues(element); - } - } - else if (j.is_object()) { - for (auto& [key, value] : j.items()) { - NormalizePrimitiveValues(value); - } - } - } - - // Any function called after this will have uninitialized variables set to zero + // Any function called after this will have uninitialized variables set to zero #ifdef WIN32 __declspec(noinline) #else __attribute__((noinline)) #endif void CleanStack() { - // stack size might need to be increased for larger classes (perhaps use alloca with class size + extra) - volatile char stack[0x10000]; - for(size_t i = 0; i < sizeof(stack); ++i) { - stack[i] = 0; - } + // stack size might need to be increased for larger classes (perhaps use alloca with class size + extra) + volatile char stack[0x10000]; + for(size_t i = 0; i < sizeof(stack); ++i) { + stack[i] = 0; + } } // Determine how and if to output metadata entry value based on it's type. @@ -169,31 +143,7 @@ namespace Dumpers::Schemas int res = SaveKV3AsJson(*(void**)value, err, buf); if (res) { - std::string out = buf.Get(); - - // Fix invalid JSON values produced by SaveKV3AsJson bug (e.g., -nan, nan) - size_t pos = 0; - while ((pos = out.find("nan", pos)) != std::string::npos) { - bool validPrefix = (pos == 0 || out[pos - 1] == ' ' || out[pos - 1] == '\t' || out[pos - 1] == '\n' || out[pos - 1] == '-'); - bool validSuffix = (pos + 3 >= out.length() || out[pos + 3] == ' ' || out[pos + 3] == '\n' || out[pos + 3] == ','); - - if (validPrefix && validSuffix) { - out[pos] = '0'; - out[pos + 1] = '.'; - out[pos + 2] = '0'; - } - ++pos; - } - - try { - auto jsonObj = json::parse(out); - NormalizePrimitiveValues(jsonObj); - return jsonObj.dump(1, '\t'); - } - catch (const json::parse_error& e) { - spdlog::warn("Failed to parse KV3 JSON for normalization: {}\nJSON content:\n{}", e.what(), out); - return out; - } + return buf.Get(); } return "Could not parse KV3 Defaults"; From b51f19309713acfc1720948d0c53449376e1655b Mon Sep 17 00:00:00 2001 From: vibecode2 Date: Sat, 4 Oct 2025 22:14:03 +0200 Subject: [PATCH 4/4] Blacklist classes with bogus kv3defaults constructor --- src/main/dumpers/schemas/metadata_stringifier.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/dumpers/schemas/metadata_stringifier.cpp b/src/main/dumpers/schemas/metadata_stringifier.cpp index 0e63ce4..84daa1a 100644 --- a/src/main/dumpers/schemas/metadata_stringifier.cpp +++ b/src/main/dumpers/schemas/metadata_stringifier.cpp @@ -30,6 +30,7 @@ #include #include "metadata_stringifier.h" #include +#include class SimpleCUtlString { public: @@ -43,6 +44,14 @@ class SimpleCUtlString { namespace Dumpers::Schemas { + std::unordered_set g_classWithBrokenDefaults = + { + "CastSphereSATParams_t", + "Dop26_t", + "FourCovMatrices3", + "VMixVocoderDesc_t", + }; + // Any function called after this will have uninitialized variables set to zero #ifdef WIN32 __declspec(noinline) @@ -121,7 +130,7 @@ namespace Dumpers::Schemas typedef void* (*GetKV3DefaultsFn)(); typedef int (*SaveKV3AsJsonFn)(void* kv3, SimpleCUtlString& err, SimpleCUtlString& str); - if (!entry.m_pData || !(*(void**)entry.m_pData) || !strcmp(metadataTargetName, "CastSphereSATParams_t")) return "Could not parse KV3 Defaults"; + if (!entry.m_pData || !(*(void**)entry.m_pData) || g_classWithBrokenDefaults.contains(metadataTargetName)) return "Could not parse KV3 Defaults"; CleanStack(); // Prepare stack for uninitialized variables in class constructor inside GetKV3Defaults auto value = reinterpret_cast(*(void**)entry.m_pData)();