From d0ff647581d6ab07e8816117b95ee83e04e4bc6d Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 6 Sep 2026 02:55:17 -0400 Subject: [PATCH] [Fix] (Pipe): re-arm the verify comparator when any of its three knobs changes, not only when PipeVerify does - ArmVerify latched PipeVerifyFatal and PipeVerifyCorrupt at the moment PipeVerify changed; a later change to either without a PipeVerify toggle was not seen, so 878db2c4's "re-parse when their value changes" held for one knob of three. - The latch now keys on all three Features values. A lane loads Features before its first fill, so it still arms once per process; cost is two Bool compares and one String compare per fill, verify builds only. --- MobileGL/MG_Impl/Pipe/PipeFill.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index e298c8f1..551678cc 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -351,6 +351,7 @@ namespace MobileGL::MG_Pipe { Bool Fatal = true; Bool InHook = false; // a re-read that re-enters an accessor is not re-verified Optional Corrupt; + String CorruptKnob; // the MOBILEGL_PIPE_VERIFY_CORRUPT value the last arm saw std::atomic Divergences{0}; ~VerifyState() { const Uint64 count = Divergences.load(std::memory_order_relaxed); @@ -362,17 +363,24 @@ 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). + // Armed on the first fill and re-armed when any of the three verify knobs' + // Features value (PipeVerify, PipeVerifyFatal, PipeVerifyCorrupt) differs from what + // the last arm latched (the same reason as ParsePoisonOmissionKnob: one arm per lane + // process, a fresh arm for a forked test child that turns a knob after its parent + // filled). Cost: two Bool compares and one String compare per fill, verify builds only. void ArmVerify() { - if (g_verify.Parsed && g_verify.Enabled == MG_Config::Features.PipeVerify) return; + const auto& features = MG_Config::Features; + if (g_verify.Parsed && g_verify.Enabled == features.PipeVerify && g_verify.Fatal == features.PipeVerifyFatal && + g_verify.CorruptKnob == features.PipeVerifyCorrupt) { + return; + } g_verify.Parsed = true; - g_verify.Enabled = MG_Config::Features.PipeVerify; + g_verify.Enabled = features.PipeVerify; + g_verify.Fatal = features.PipeVerifyFatal; + g_verify.CorruptKnob = features.PipeVerifyCorrupt; g_verify.Corrupt = Optional{}; if (!g_verify.Enabled) return; - g_verify.Fatal = MG_Config::Features.PipeVerifyFatal; - const String& corrupt = MG_Config::Features.PipeVerifyCorrupt; + const String& corrupt = g_verify.CorruptKnob; if (!corrupt.empty()) { const auto field = MGPipeFindInputField(corrupt.c_str()); if (!field) {