File size: 5,474 Bytes
6dafc4b 6787ca3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # Client snapshot area-mask parsing
Reproduce with `python3 scripts/analyze_client_masks.py`; validate with `python3 scripts/test_client_masks.py`. [client-masks.json](client-masks.json) retains three hash-verified graphs from the Linux ELF64 client: CL_ParseSnapshot, MSG_ReadByte and MSG_ReadData. This follows the server [mask serialization requests](SNAPSHOT_AREAS.md).
These are bounded synthetic instruction evaluations. Original processes and every native callee remain unexecuted. Frame PUSH/POP instructions are explicitly omitted, virtual stack addresses supplied, and caller registers retained across stopped helpers. MSG_ReadBits return words and post-call readcounts are supplied; neither real packet decoding nor Huffman/cursor behavior is established. Only the Linux client is sampled, not dedicated-server equivalence or other platforms.
## CLIENT-001 — Reset, unsigned length guards and destination (RE-337)
At entry 0x4207d2, the parser requests memset of its temporary snapshot: destination virtual stack, value zero, size 0x21c (540 bytes). Three PUSH instructions are omitted for this argument probe, and the pre-subtraction stack pointer is supplied explicitly. The memset call itself does not execute. Data compositions supply its zero-fill effects, retaining outside canaries.
Two paths read the mask-length byte and test it against 32: comparisons at 0x42088f and 0x4208ed use unsigned JBE/JA respectively. Twenty-two probes accept 0,1,7,31,32 and reject 33,127,128,255,0xffffffff,0x80000000 on both paths. Rejected paths request Com_Error with error code 1, the supplied length word and the verified string `CL_ParseSnapshot: Invalid size %d for areamask.` The error function is not executed.
Both accepted paths request MSG_ReadData(message, temporary_snapshot +0x18, length) at 0x4208fc. Length zero remains accepted. The byte-reader EOF word 0xffffffff fails this unsigned guard. These offsets describe this native Linux layout, not the server's different frame layout or a Rust ABI.
## CLIENT-002 — Byte-reader cursor boundary (RE-338)
MSG_ReadByte at 0x44dec4 requests MSG_ReadBits(message,8). Its post-call slice compares message.readcount at +0x20 against message.cursize at +0x1c using signed CMOVLEL. If readcount <= cursize, it returns the supplied result's low eight bits, zero-extended; otherwise it returns 0xffffffff. The POP is explicitly omitted; evaluation stops before RET.
Two hundred ten probes cover sizes 0,1,32,0x7fffffff,0xffffffff; cursors 0,1,2,32,33,0x80000000,0xffffffff; and six return words including 0x1234 and 0xffffffff. Equality is accepted. Negative signed cursor/size fixtures characterize the comparison locally; they do not establish legal message states. Low-byte 0xff is distinguishable from EOF 0xffffffff at this helper's return boundary.
## CLIENT-003 — Exact requested copy and truncation (RE-339)
MSG_ReadData at 0x45307a uses a signed length <=0 early exit. For positive lengths, it requests eight bits once per destination byte through an initial byte, peeled remainder and four-byte unrolled loop. Each lane compares the supplied post-read cursor with cursize; on overflow it stores 0xff, otherwise the returned low byte. It continues requesting and storing the entire length after overflow rather than exiting at the first failed read.
Fifty-three compositions cover lengths -1,0,1 through 9,16,17,31,32 with sizes drawn from zero, one, length-minus-one and length. Supplied post-readcounts are 1 through length, and supplied result words cycle through 0,127,128,255,0x1234,0xffffffff. Negative/zero lengths issue no requests or writes. Every positive fixture has exactly length requests `(message,8)`; overflow bytes become 0xff. The unused mask tail retains the supplied reset's zeros, and frame canaries remain unchanged.
The server requests only its mask's used byte span; the client guard caps that span at 32 and targets a zero-initialized temporary buffer. This establishes compatible bounded pointer/count relationships, not a server-to-client wire round trip. Real MSG_ReadBits can use compressed bit cursors, so the supplied ordinal readcounts are explicit test inputs, not a recovered cursor update formula. Complete post-copy bad-message checks, delta validity and snapshot publication remain open.
## Validation and next work
Eight independent tests cover reset arguments, both unsigned guards and error arguments, signed cursor/low-byte return, exact copy requests and bytes, continued EOF requests, canaries/tails/unrolled lengths, stopped CALL boundaries, and restricted evaluator CMOVLEL/BL semantics with unknown-flag rejection. Reports include source/disassembly hashes and native trace addresses or hashes. The evaluator extension adds only signed conditional move and the BL register alias.
RE-340: recover actual bit/Huffman encoding and readcount updates, message overflow/bad-read handling, all snapshot/delta/player/entity validation and publication, mask renderer interpretation and map-area validity; compose real encoded packets and original-runtime/all-platform fixtures. Implement Rust protocol/Bevy/Solari integration only against a complete validated contract.
Bit-reader follow-up: [message modes and assembly](MESSAGE_BITS.md) recovers bounded OOB reads, raw bit instructions and compressed cursor/sign-tail behavior (RE-341–343). Huffman symbols/code lengths remain supplied; real packet decoding and full snapshot validation remain open.
|