From 878db2c405c2164fbc39c5b196c8c135b5036182 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 6 Sep 2026 02:31:56 -0400 Subject: [PATCH] [Fix] (Pipe): re-parse the POISON_OMIT and VERIFY knobs when their Features value changes, not once per process - The two parsers (ParsePoisonOmissionKnob, ArmVerify) latched on the first fill, so the only way to reach them was a lane that loads MG_Config::Features before any fill; no unit test could exercise the parse, the arming lines or Fatal{PipeVerifyBadKnob}. - The latch now keys on the value: a lane still parses once (Features is loaded before the first fill), while a forked test child that sets Features after its parent filled gets its own parse. An empty omission value never clears an omission armed through MGPipeSetPoisonOmission. - Re-arming resets the CORRUPT field so a stale corruption cannot outlive the knob that named it. --- MobileGL/MG_Impl/Pipe/PipeFill.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index 33891ec1..6537838b 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -296,11 +296,18 @@ namespace MobileGL::MG_Pipe { }; PoisonOmission g_omission; Bool g_omissionKnobParsed = false; + String g_omissionKnobValue; // the value the last parse saw + // Parsed on the first fill and again only when the value changes. A lane loads + // Features once, before any fill, so that is one parse per process there; a forked + // test child that sets Features after its parent already filled gets its own parse, + // which is what puts the parser and its Fatal{PipeVerifyBadKnob} under a unit test. + // An empty value never clears an omission a test armed through MGPipeSetPoisonOmission. void ParsePoisonOmissionKnob() { - if (g_omissionKnobParsed) return; - g_omissionKnobParsed = true; const String& knob = MG_Config::Features.PipePoisonOmit; + if (g_omissionKnobParsed && knob == g_omissionKnobValue) return; + g_omissionKnobParsed = true; + g_omissionKnobValue = knob; if (knob.empty()) return; const auto colon = knob.find(':'); if (colon == String::npos || colon == 0 || colon + 1 >= knob.size()) { @@ -348,10 +355,14 @@ namespace MobileGL::MG_Pipe { }; VerifyState g_verify; + // Armed on the first fill and re-armed only when Features.PipeVerify changes (the + // same reason as ParsePoisonOmissionKnob: one arm per lane process, a fresh arm for a + // forked test child that turns the knob on after its parent filled unarmed). void ArmVerify() { - if (g_verify.Parsed) return; + if (g_verify.Parsed && g_verify.Enabled == MG_Config::Features.PipeVerify) return; g_verify.Parsed = true; g_verify.Enabled = MG_Config::Features.PipeVerify; + g_verify.Corrupt = Optional{}; if (!g_verify.Enabled) return; g_verify.Fatal = MG_Config::Features.PipeVerifyFatal; const String& corrupt = MG_Config::Features.PipeVerifyCorrupt;