[MG_Pipe, MG_Backend, MG_Remote, MG_Test, scripts] (P7): the Magma wire fatals and the two Staged aborts go through Session::Fail

Five deaths in the split server image raised their own std::abort(). Three of them are
funnels - MagmaWireFatal (Renderer/WireFramebuffer.inc), WireDescriptorFatal
(Renderer/UniformManager.cpp) and WireBufferLegacyFatal (Renderer/WireDraw.inc) - and the
fifteen `@P7` refusals on the tree (8 in UniformManager.cpp, 4 in WireFramebuffer.inc, 2 in
WireDraw.inc, 1 in VulkanRenderer.cpp; plan section 1.3's count confirmed) all die through
two of them. Every one of those deaths published NO SessionFault frame, so the peer read a
bare EOF; bumped NO SessionFaultCount(), so exit gate S8 could neither confirm nor falsify
it; and carried a hand-typed family word with no path to FatalFamilies.def's projection.

MG_Backend may not name an MG_Remote symbol on its own account, so the route is a seam in
MG_Pipe with MGP_TRIP_WIRE_REPORT's shape (PipeApply.cpp:66, and the new code sits beside
it): MG_Pipe/PipeSessionFail.h declares MGPipeSessionFail, PipeApply.cpp defines it inside
`#if MOBILEGL_BUILD_DISAGGREGATED`, the DEFAULT behaviour is byte-identical to what the
three funnels did on their own, and MG_Remote::InstallPipeSessionFailHook() points it at
SessionFail. The install is in InitServerRoleCommon (MG_Backend/Init.cpp), step 0, because
that is the one function BOTH server roles run - the inproc role and the spawn/TCP session
child - so there is no per-transport install to get wrong.

MGPipeFatalFamily is a two-value boundary enum, NOT MGFatalFamily cast to an integer: the
.def's enumerators are positional and a row inserted in its middle would silently re-point
every hook call at a different family. FatalFunnel.cpp's adapter is the one place the two
vocabularies meet, as a switch with a named default.

The family word stays UnmigratedVerb rather than becoming a new MagmaWireRefusal. Three
reasons: the message strings are required to stay byte-identical (5.2), and the retrace
refusal censuses recorded since P5b count these deaths by that word - a rename invalidates
every `@P7` measurement taken against them; `Magma:` in the detail already separates the
Magma arm from the GLES UnmigratedVerb deaths, so a new word adds no discrimination a grep
does not have; and its wire projection would be ProtocolCorruption, exactly UnmigratedVerb's.
Recorded for the integrator.

Ph slice (2) in the same commit: Server/StagedShadow.h's RequireCovered and
Server/StagedTextureStore.h's RequireLevelBytes were MGLOG_F + bare abort. Both are inside
MG_Remote already, so they call SessionFail directly, message verbatim;
check_include_closure.py's four probes do not reach either header and the gate is green.

Census: 83 abort sites -> 79 over 20 files (five sites retired, one gained for the seam's
no-hook default, which is argued into FUNNEL_SITES), baseline rewritten in this commit - the
downward ratchet's notice is what asked for it. Two gate bugs the widening exposed and this
commit fixes: the SessionFail call regex also matched `MGPipeSessionFail(` (a lookbehind
now), and a funnel's anchor needed a wider window than a marker's (kFunnelAnchorWindow).

Red-once, three ways. Pointing MagmaWireFatal back at its own abort reds the census naming
WireFramebuffer.inc 0 -> 1. Making the seam skip the hook reds both new death cases -
`TheMagmaWireVerbDeathReachesSessionFailAndBumpsTheFaultCount` on the exit code, because it
reads SessionFaultCount() out of a SIGABRT handler and gets 0 instead of 1, and
`TheSeamHandsTheInstalledHookItsFamilyAndItsLineVerbatim` on the line the hook echoed.
This commit is contained in:
2026-09-22 14:01:06 -04:00
parent f141918aa1
commit e1ec69341a
14 changed files with 333 additions and 21 deletions
+20 -4
View File
@@ -124,6 +124,10 @@ FUNNEL_SITES = {
("#define MGP_TRIP_WIRE_REPORT",
"the poison/verify trip-wire funnel: its 30-odd callers each pass MGP_TRIP_WIRE_TAG(name), "
"which IS the `Fatal{name}` marker, so the death is named by the caller"),
("void MGPipeSessionFail(",
"the no-hook default of the backend session-fail seam (MG_Pipe/PipeSessionFail.h): the "
"line it logs is the CALLER's, family word and all, and with MG_Remote's hook installed "
"this abort is never reached at all"),
),
"MobileGL/MG_Pipe/generated/PipeWire.inc": (
("MGPipeWireProtocolFatal",
@@ -138,6 +142,13 @@ FUNNEL_SITES = {
# abort it has nothing to do with.
kMarkerWindow = 12
# A FUNNEL'S ANCHOR GETS A WIDER WINDOW THAN A MARKER DOES, and for the opposite reason. A marker
# window has to be tight because any `Fatal{` in it silences the abort below; an anchor window can
# be loose because the anchor is a specific line of code, argued for by name in the table above,
# and the only thing a wider window can reach is the same funnel's own body. Forty covers a funnel
# whose signature and abort are separated by its formatting and its explanation.
kFunnelAnchorWindow = 40
MARKER = re.compile(r"Fatal\{([A-Za-z][A-Za-z0-9]*)")
REFUSAL = re.compile(r"Refuse\{([A-Za-z][A-Za-z0-9]*)")
ABORT = re.compile(r"\bstd::abort\(\)")
@@ -145,7 +156,11 @@ WIRE_LOG_FATAL_CALL = re.compile(r"WireLogFatal\s*\(")
# P6 dl: a SessionFail call must carry a Fatal{ word in its string, the same rule
# WireLogFatal has - the enum and the string both name the family, and a call whose string
# forgot it would let the two disagree. Checked everywhere SessionFail is called.
SESSION_FAIL_CALL = re.compile(r"SessionFail\s*\(")
#
# The lookbehind is not decoration: without it this pattern also matches `MGPipeSessionFail(`,
# and it reported MG_Pipe's own seam - whose callers carry the word exactly as SessionFail's do -
# for being a SessionFail call with no word in its DECLARATION.
SESSION_FAIL_CALL = re.compile(r"(?<![A-Za-z0-9_])SessionFail\s*\(")
FAMILY_ROW = re.compile(r"^\s*X\(([A-Za-z][A-Za-z0-9]*)\s*,", re.MULTILINE)
REFUSE_ENUM = re.compile(r"enum\s+RefuseCode\s*:[^{]*\{(.*?)\}", re.DOTALL)
ENUM_VALUE = re.compile(r"^\s*([A-Za-z][A-Za-z0-9]*)\s*=", re.MULTILINE)
@@ -245,11 +260,11 @@ def declared_refusals():
return set(ENUM_VALUE.findall(block.group(1)))
def sanctioned(rel, window):
def sanctioned(rel, anchor_window):
"""Is this unmarked abort inside a funnel the tables above sanction?"""
if rel in FUNNEL_FILES:
return True
return any(anchor in window for anchor, _reason in FUNNEL_SITES.get(rel, ()))
return any(anchor in anchor_window for anchor, _reason in FUNNEL_SITES.get(rel, ()))
def census():
@@ -287,7 +302,8 @@ def census():
continue
sites.append({"file": rel, "line": index + 1})
window = "\n".join(lines[max(0, index - kMarkerWindow):index + 1])
if sanctioned(rel, window):
anchors = "\n".join(lines[max(0, index - kFunnelAnchorWindow):index + 1])
if sanctioned(rel, anchors):
continue # rule 2, or an argued funnel entry, covers it
if not MARKER.search(window):
unmarked.append({"file": rel, "line": index + 1, "text": line.strip()})
+2 -7
View File
@@ -1,5 +1,5 @@
{
"abort_sites": 83,
"abort_sites": 79,
"abort_sites_by_file": {
"MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp": 15,
"MobileGL/MG_Backend/DirectGLES/Managers.cpp": 12,
@@ -7,22 +7,17 @@
"MobileGL/MG_Backend/DirectGLES/Utils.cpp": 1,
"MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp": 2,
"MobileGL/MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h": 1,
"MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp": 1,
"MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp": 11,
"MobileGL/MG_Backend/DirectVulkan/Renderer/WireDraw.inc": 1,
"MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc": 1,
"MobileGL/MG_Backend/Init.cpp": 2,
"MobileGL/MG_Backend/MGPipe/PipeInputs.cpp": 3,
"MobileGL/MG_Impl/Pipe/PipeFill.cpp": 5,
"MobileGL/MG_Impl/Pipe/ResourceTracker.h": 5,
"MobileGL/MG_Impl/Pipe/SlotAllocator.cpp": 2,
"MobileGL/MG_Pipe/PipeApply.cpp": 3,
"MobileGL/MG_Pipe/PipeApply.cpp": 4,
"MobileGL/MG_Pipe/PipeRoute.cpp": 7,
"MobileGL/MG_Pipe/generated/PipeFilled.inc": 1,
"MobileGL/MG_Pipe/generated/PipeWire.inc": 1,
"MobileGL/MG_Remote/FatalFunnel.cpp": 1,
"MobileGL/MG_Remote/Server/StagedShadow.h": 1,
"MobileGL/MG_Remote/Server/StagedTextureStore.h": 1,
"MobileGL/MG_Remote/Transport/WireLog.cpp": 1,
"MobileGL/MG_State/GLState/BufferState/BufferObject.cpp": 2,
"MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp": 1