D125: fix d88_emit.py:374 8-byte slice / 4-byte literal (Aztec C3 crash)

emit_pad()'s widened-stan zero-fill assigned a 4-byte literal to an
8-byte bytearray slice. Python slice-assign with a short RHS silently
deletes the surplus bytes, so `out` shrank 4 B per pad+boundpad; once
len(out) dropped below a later leaf write's target offset, the write
clamped to empty-at-end and inserted there, drifting/truncating the
boundpad plink-name blob (Aztec pad33 "p138d2" -> "8d2") -> stanPackId
reject -> NULL stan -> door model=NULL -> crash propobj.c:13601.

Fix: 8 NUL bytes (only width-mismatched out[ write in the file).
All 21 Usetup*Z sidecars regenerated. Aztec (-level_28) now PASSES
(was C3 CRASH); Bunker1/Silo unregressed; d125_check.py 21/21 MATCH.
Sweep 12 -> 13/21.

Bunker2 (-level_27) still crashes: separate DOOR-tail linkedDoor
layout bug in d88_propdefs.py (C3r) -- linkedDoor is resolved from
linkedDoorOffset (read-before-write int id, D123 pattern). Folded
into the converter write-audit.

M-16 probes reverted; d125_check.py kept as the offline regression guard.
Generalisable quirk added to PORT-LEARNINGS.md §C.
This commit is contained in:
James Dansereau committed 2026-08-29 19:12:52 -04:00
1 parent 710d0b12b5
commit 060a7252e5
6 files changed
+279 -71

No files matched your search

+4 -1
View File
@@ -371,7 +371,10 @@ def convert_usetup(name, src):
out[dst_o + 0x2c:dst_o + 0x30] = b"\x00\x00\x00\x00"
# stan: dead-on-load (init_pathtable_something always sets it before
# use, D88 same class as D79) -- zero it, never read from file.
out[dst_o + 0x30:dst_o + 0x38] = b"\x00\x00\x00\x00"
# NOTE: this slice is 8 bytes wide (widened stan ptr); the RHS MUST be
# 8 NUL bytes -- a 4-byte literal here makes `out` SHRINK by 4 per pad
# via Python slice-assign semantics, drifting every later region (D125).
out[dst_o + 0x30:dst_o + 0x38] = b"\x00\x00\x00\x00\x00\x00\x00\x00"
if has_bbox:
for k in range(6):
v = be32(src, src_o + 0x2c + 4 * k)