mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-15 22:13:24 +09:00
[scripts, MG_Remote, MG_Impl, MG_Test] (P7): the fatal census gate widened to the split server image
`scripts/ci/fatal_census.py` scanned `MG_Remote/` and saw four abort sites. CONTRACT-P6
§12.1 already says what the server image is - "P6's server image is the whole
libMobileGL.so" - and the server process was executing seventy-nine more deaths the gate
could not see: 15 in DirectGLES.cpp, 12 in Managers.cpp, 11 in VkBufferManager.cpp, 7 in
PipeRoute.cpp. SCAN_ROOTS is now MG_Remote / MG_Pipe / MG_Backend / MG_Impl/Pipe /
MG_State, `.inc` joins `.cpp`/`.h` (the Magma wire arms and the generated wire records are
.inc files, and 20 sites are reachable only through one), and MG_Benchmark /
MG_IntegrationTest join MG_Test in the exclusion.
Four rules now, where there were two:
1. an abort names its family within twelve lines, OR it is argued into FUNNEL_FILES /
the new FUNNEL_SITES table. FUNNEL_SITES exempts an individual funnel inside a file
that has ordinary named deaths around it, and only when one of the file's anchors
appears in the same window - so the exemption follows the funnel if it moves, expires
if it is deleted, and does not cover an unrelated abort added to the same file. Two
entries, one line of reason each: PipeApply.cpp's MGP_TRIP_WIRE_REPORT and
PipeWire.inc's MGPipeWireProtocolFatal.
2. unchanged: a WireLogFatal / SessionFail call carries a `Fatal{` in its string.
3. NEW: every family word found in the perimeter has a row in FatalFamilies.def. Eleven
words did not, and now do (see below).
4. NEW: every `Refuse{Word}` names a RefuseCode enumerator. This is what catches
`Refuse{AuthenticationRequired}` (SocketTransport.cpp:161), a word protocol.fbs has
never had - PH-7 (2). Renamed to the enum's own `Authentication`, and
SocketTransportTest pins the spelling to `EnumNameRefuseCode` so the two cannot
drift again.
`abort_sites` was recorded and never compared. It is now a DOWNWARD ratchet with a
per-file map beside it, so "83 became 84" reports as "VkBufferManager.cpp went 11 -> 12,
here are its lines"; fewer sites - the direction `@P7` retirement moves the number - asks
for a re-baseline rather than blocking one.
Eleven new `.def` rows for the eleven rowless words. Ten are ProtocolCorruption for the
reason that bucket already states. ResourceUnavailable is ServerCrashed, not SegmentMismatch:
SegmentMismatch means a shared SEGMENT was the wrong size, and telling a peer that when a
VkBuffer allocation failed would be a lie about whose geometry was wrong. A twelfth word was
collapsed rather than given a row - `InitialBytesNotCarried` (PipeFill.cpp) said the same
thing as `UncarriedInitialBytes` (WireTables.cpp) about the same record, and two words for
one family is the drift a6 censused.
Red-once, four ways: an unnamed `std::abort()` appended under MG_State reds naming the file
and the line; deleting the `Fatal{` from PipeRoute.cpp's ResidualBlockSize reds; putting
`Refuse{AuthenticationRequired}` back reds rule 4; a typo'd family word reds rule 3 and the
vocabulary ratchet together.
This commit is contained in:
@@ -985,7 +985,11 @@ namespace MobileGL::MG_Pipe {
|
||||
const Uint64 before = MG_Remote::Client::ClientWireRecordsEmitted();
|
||||
MGPipeEmitResourceSubData(buffer, 0, static_cast<SizeT>(buffer.GetSize()));
|
||||
if (MG_Remote::Client::ClientWireRecordsEmitted() == before) {
|
||||
MGLOG_F("MGPipe: Fatal{InitialBytesNotCarried, \"resource_respecify\"} - the "
|
||||
// UncarriedInitialBytes, not a second word for the same family: WireTables.cpp:418
|
||||
// already dies of exactly this - a respecify that crossed with no initial bytes -
|
||||
// under that name, and two words for one family is the vocabulary drift a6
|
||||
// censused and 5.2's .def exists to bound (P7 wave 0).
|
||||
MGLOG_F("MGPipe: Fatal{UncarriedInitialBytes, \"resource_respecify\"} - the "
|
||||
"respecify crossed with initialBytes = nullptr (R-13.3) and the "
|
||||
"resource_subdata records that were supposed to follow it emitted "
|
||||
"NOTHING, so %llu bytes of initial content exist on no side of the wire",
|
||||
|
||||
@@ -33,12 +33,29 @@
|
||||
// not merely full this instant.
|
||||
// AbiMismatch - the two builds do not agree on layout or protocol version.
|
||||
// ServerCrashed - a liveness end the WAITING side attributes to the other: a drain that
|
||||
// never completed, an apply thread that is gone or never started. The
|
||||
// device-lost latch is armed from the doorbell, never from these, but the
|
||||
// peer that was waiting is told the server is gone.
|
||||
// never completed, an apply thread that is gone or never started, a native
|
||||
// resource the server had to have and could not obtain. The device-lost
|
||||
// latch is armed from the doorbell, never from these, but the peer that
|
||||
// was waiting is told the server is gone.
|
||||
// DeviceLost - reserved: set by the latch (5.3), never raised as a Fatal family, so no
|
||||
// row projects onto it.
|
||||
//
|
||||
// P7 WAVE 0 ADDED ELEVEN ROWS, for the eleven words the widened census gate found in the server
|
||||
// image outside MG_Remote/ (scripts/ci/fatal_census.py rule 3). Ten are ProtocolCorruption for
|
||||
// the reason that bucket already states - a record, a mask or a reply that cannot be honoured
|
||||
// correctly. The eleventh, ResourceUnavailable (Managers.cpp's three image-promotion sites and
|
||||
// VkBufferManager.cpp's eight), is ServerCrashed rather than SegmentMismatch: SegmentMismatch
|
||||
// means a SHARED SEGMENT was the wrong size, and telling a peer that when a VkBuffer allocation
|
||||
// or a native readback failed would be a lie about whose geometry was wrong. The honest thing to
|
||||
// tell a waiting peer is the one ServerCrashed already says. The wire enum has no "the server
|
||||
// could not obtain a resource" value and adding one would move `wireFingerprint`, which is a
|
||||
// protocol change no wave-0 instrument is entitled to make (recorded for the integrator).
|
||||
//
|
||||
// Two words were NOT given rows, they were collapsed instead: `InitialBytesNotCarried`
|
||||
// (MG_Impl/Pipe/PipeFill.cpp) said the same thing as `UncarriedInitialBytes` (Client/
|
||||
// WireTables.cpp) about the same record - a respecify that crossed with no initial bytes - and
|
||||
// two words for one family is exactly the drift a6 censused. PipeFill now uses the older word.
|
||||
//
|
||||
// clang-format off
|
||||
|
||||
// X(Family, WireFatalCode, Why)
|
||||
@@ -47,16 +64,26 @@
|
||||
X(UnmigratedVerb, ProtocolCorruption, "a wire verb slot P5/P6 does not implement was reached") \
|
||||
X(UnmigratedSurface, ProtocolCorruption, "a surface op named a client-process handle that means nothing here (P12)") \
|
||||
X(UnmigratedPipeInput, ProtocolCorruption, "a PipeInputs field with no field-ownership row was read across the boundary") \
|
||||
X(UnmigratedEmulation, ProtocolCorruption, "an emulation path the applier has no migrated arm for was reached") \
|
||||
X(RoleViolation, ProtocolCorruption, "a call ran on the wrong role/thread - an invariant the two roles must hold") \
|
||||
X(UnsetCallMask, ProtocolCorruption, "the CallMask was consulted before either half was published") \
|
||||
X(ConsumerMaskLie, ProtocolCorruption, "the server published a consumer bit for a family whose op table is absent") \
|
||||
X(ClientTablesUninstalled, ProtocolCorruption, "the applier ran before the client installed its tables") \
|
||||
X(NoClientSession, ProtocolCorruption, "a path that needs the client session ran without one") \
|
||||
X(UnnamedIdentity, ProtocolCorruption, "a per-context memo was consulted with a null context identity") \
|
||||
X(PipeLegacyMemosDisabled, ProtocolCorruption, "a subsystem bit is clear and this build compiles no legacy arm to fall back to") \
|
||||
X(PipeVerifyBadKnob, ProtocolCorruption, "a MOBILEGL_PIPE_VERIFY/POISON knob named a verb or field that does not exist") \
|
||||
X(PipeVerifyDiffer, ProtocolCorruption, "the verify comparator found a pushed field differing from the live one") \
|
||||
X(UnexpectedMapAccept, ProtocolCorruption, "a persistent-map accept arrived where the protocol permits none") \
|
||||
X(UncarriedInitialBytes, ProtocolCorruption, "a producer's initial bytes were required on the wire and absent") \
|
||||
X(ReplyStatusInvalid, ProtocolCorruption, "a reply carried a status outside the defined set") \
|
||||
X(ReplyError, ProtocolCorruption, "a reply-owning verb saw an error status it cannot represent") \
|
||||
X(ReplyMissing, ProtocolCorruption, "a reply slot the protocol requires was empty") \
|
||||
X(ReplyMismatched, ProtocolCorruption, "the reply mailbox held an answer for a different slot than the one waited on") \
|
||||
X(ReplyOverrun, ProtocolCorruption, "an answer was posted while a previous one was still unread") \
|
||||
X(ReplyToNoSlot, ProtocolCorruption, "an answer was posted against reply slot 0, which means \"no record\"") \
|
||||
X(ReplyTooLarge, ProtocolCorruption, "an answer exceeded the size its verb's contract allows") \
|
||||
X(ResidualBlockSize, ProtocolCorruption, "a fixed-size residual block arrived at a size that is not its own") \
|
||||
X(ReadbackDeclined, ProtocolCorruption, "a readback that cannot return without complete pixels was declined") \
|
||||
X(ReadbackReplyShort, ProtocolCorruption, "a readback reply carried fewer bytes than its shape requires") \
|
||||
X(UnsizedReadback, ProtocolCorruption, "a readback arrived with no declared size") \
|
||||
@@ -77,6 +104,7 @@
|
||||
X(PresentCreditTimeout, ServerCrashed, "a present credit did not return within the bounded wait") \
|
||||
X(RetirementWaitFailed, ServerCrashed, "a wait for the server to retire staging did not complete") \
|
||||
X(ApplyThreadJoinTimeout, ServerCrashed, "the apply thread did not join within its bound at teardown") \
|
||||
X(ApplyThreadNotRunning, ServerCrashed, "an operation needed the apply thread and it was not running")
|
||||
X(ApplyThreadNotRunning, ServerCrashed, "an operation needed the apply thread and it was not running") \
|
||||
X(ResourceUnavailable, ServerCrashed, "the server could not obtain a native GL/Vulkan resource it had to have")
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -158,7 +158,11 @@ namespace MobileGL::MG_Remote::Transport {
|
||||
MobileGLResult result = MOBILEGL_ERR_UNSUPPORTED;
|
||||
for (auto* address = addresses; address; address = address->ai_next) {
|
||||
if (!authenticated && !Loopback(address->ai_addr)) {
|
||||
WireLogError("MG_Remote: Refuse{AuthenticationRequired} non-loopback TCP listen needs MOBILEGL_IPC_TOKEN");
|
||||
// The word is RefuseCode's own enumerator. It read `AuthenticationRequired`
|
||||
// for a whole phase, naming a value protocol.fbs has never had, so a reader
|
||||
// grepping the refusal vocabulary found a word the wire cannot carry (PH-7
|
||||
// (2)); fatal_census.py's rule 4 now refuses that.
|
||||
WireLogError("MG_Remote: Refuse{Authentication} non-loopback TCP listen needs MOBILEGL_IPC_TOKEN");
|
||||
result = MOBILEGL_ERR_PROTOCOL_MISMATCH;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
// `BufferTooSmallKeepsTheMessage` matters more here: the message it must keep
|
||||
// is one this side already reassembled out of bytes nobody else can re-deliver.
|
||||
|
||||
#include <MG_Remote/Protocol/generated/protocol_generated.h> // RefuseCode, for the word below
|
||||
#include <MG_Remote/Transport/Doorbell.h> // kWaitForever
|
||||
#include <MG_Remote/Transport/FdPassing.h>
|
||||
#include <MG_Remote/Transport/SocketTransport.h>
|
||||
@@ -119,6 +120,14 @@ TEST(SocketTransportTest, TcpRejectsMalformedNamesAndUnauthenticatedWildcard) {
|
||||
::unsetenv("MOBILEGL_IPC_TOKEN");
|
||||
EXPECT_EQ(SocketTransport::Listen("tcp://0.0.0.0:40613", &listener), MOBILEGL_ERR_PROTOCOL_MISMATCH);
|
||||
EXPECT_EQ(listener, -1);
|
||||
// PH-7 (2). The refusal that path logs is `Refuse{Authentication}`, and `Authentication` has
|
||||
// to be RefuseCode's own spelling: for a whole phase it read `Refuse{AuthenticationRequired}`,
|
||||
// a word the wire enum has never had, so anyone grepping the refusal vocabulary found a name
|
||||
// no peer could ever receive. fatal_census.py's rule 4 refuses an invented word statically;
|
||||
// this pins the word that gate checks against to the enumerator the peer actually reads, so
|
||||
// renaming the enumerator without the log line fails here rather than silently.
|
||||
EXPECT_STREQ(MobileGL::Wire::EnumNameRefuseCode(MobileGL::Wire::RefuseCode::Authentication),
|
||||
"Authentication");
|
||||
if (wasSet) ::setenv("MOBILEGL_IPC_TOKEN", saved.c_str(), 1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user