2026-01-25 23:16:07 -03:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| TestJsonHardening.mq5 |
|
|
|
|
|
//| AI-Toolkit |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property script_show_inputs
|
2026-01-25 23:39:19 -03:00
|
|
|
#include "../fast_json.mqh"
|
2026-01-25 23:16:07 -03:00
|
|
|
|
2026-01-25 23:39:19 -03:00
|
|
|
void OnStart() {
|
|
|
|
|
Print("=== JSON HARDENING & ROBUSTNESS TEST ===");
|
2026-01-25 23:16:07 -03:00
|
|
|
|
2026-01-25 23:39:19 -03:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// 1. PRETTY PRINT
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
Print("\n--- 1. Pretty Print Test ---");
|
|
|
|
|
string raw = "{\"a\":1,\"b\":[true,false,null,{\"x\":99.9}]}";
|
|
|
|
|
CJson pp_doc;
|
|
|
|
|
if (pp_doc.Parse(raw)) {
|
|
|
|
|
string pretty = pp_doc.Serialize(true); // true = pretty
|
|
|
|
|
Print("Pretty Output:\n", pretty);
|
|
|
|
|
// Check for newlines
|
|
|
|
|
if (StringFind(pretty, "\n") >= 0 && StringFind(pretty, " ") >= 0)
|
|
|
|
|
Print("PASS: Pretty Print indentation detected.");
|
|
|
|
|
else
|
|
|
|
|
Print("FAIL: Pretty Print failed.");
|
|
|
|
|
}
|
2026-01-25 23:16:07 -03:00
|
|
|
|
2026-01-25 23:39:19 -03:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// 2. ERROR CONTEXT (Line/Col)
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
Print("\n--- 2. Error Context (Line/Col) ---");
|
|
|
|
|
string bad_json = "{\n \"valid\": 1,\n \"broken\": UNQUOTED_VALUE\n}";
|
|
|
|
|
CJson bad_doc;
|
|
|
|
|
if (!bad_doc.Parse(bad_json)) {
|
|
|
|
|
int line, col;
|
|
|
|
|
bad_doc.GetErrorPos(line, col);
|
|
|
|
|
Print("Error Code: ", EnumToString((EnumJsonError)bad_doc.GetLastError()));
|
|
|
|
|
Print("Location: Line ", line, ", Col ", col);
|
2026-01-25 23:16:07 -03:00
|
|
|
|
2026-01-25 23:39:19 -03:00
|
|
|
// "broken": starts at line 3. Value starts after.
|
|
|
|
|
// 1: {
|
|
|
|
|
// 2: "valid": 1,
|
|
|
|
|
// 3: "broken": UNQUOTED_VALUE
|
|
|
|
|
// The error should be around Line 3, Col ~13
|
|
|
|
|
|
|
|
|
|
if (line == 3 && col > 10)
|
|
|
|
|
Print("PASS: Error location accurate.");
|
|
|
|
|
else
|
|
|
|
|
Print("FAIL: Error location mismatch. Expected Line 3.");
|
|
|
|
|
} else {
|
|
|
|
|
Print("FAIL: Should have failed parsing!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// 3. STACK OVERFLOW ATTACK
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
Print("\n--- 3. Stack Exhaustion Attack ---");
|
|
|
|
|
CJsonBuilder bomb_b(65536);
|
|
|
|
|
|
|
|
|
|
// Create depth > 512
|
|
|
|
|
int depth = 600;
|
|
|
|
|
string deep = "";
|
|
|
|
|
for (int i = 0; i < depth; i++)
|
|
|
|
|
deep += "[";
|
|
|
|
|
|
|
|
|
|
// We manually construct string because Builder might check sp too (which is
|
|
|
|
|
// good) But we want to test PARSER safety.
|
2026-01-25 23:16:07 -03:00
|
|
|
|
2026-01-25 23:39:19 -03:00
|
|
|
Print("Parsing Depth: ", depth);
|
|
|
|
|
CJson bomb_doc;
|
|
|
|
|
// This should return false, NOT CRASH
|
|
|
|
|
// If it crashes, this script stops dead.
|
|
|
|
|
|
|
|
|
|
bool res = bomb_doc.Parse(deep);
|
|
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
|
int err = bomb_doc.GetLastError();
|
|
|
|
|
Print("Parse Result: Error ", EnumToString((EnumJsonError)err));
|
|
|
|
|
if (err == JSON_ERR_STACK_OVERFLOW)
|
|
|
|
|
Print("PASS: Stack Overflow caught gracefully.");
|
|
|
|
|
else
|
|
|
|
|
Print("FAIL: Wrong error code.");
|
|
|
|
|
} else {
|
|
|
|
|
Print("FAIL: Should have failed deep recursion!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Print("\n=== SUITE COMPLETE ===");
|
|
|
|
|
}
|