Fix EXEC/LOAD block-persistence gap and WIREBIND/USE interpreter-race panic (FABRIC-3.md §XII)
Found live while building a cross-ISA FORTH-79 dictionary exerciser: - capsule_exec_init() zeroed a capsule's block content immediately after running it, so LOAD (a genuine FORTH-79 standard word, ACL-allowed even for locked identities) could never actually read back what EXEC had just written. Removed the clear from capsule_exec_init(); block content now persists like any other Standard BLOCK/BUFFER/UPDATE write. kernel_main.c's own explicit post-birth clear of Mama's init.4th range is untouched. - USE could redirect the console to a WIREBIND identity's VM before that VM's vm_enable_interpreter() step of its own birth sequence had run, causing the next typed line to hit vm_assert_interpreter_enabled() and panic the entire machine -- not the per-session-recoverable ACL-fault path a redirected VM otherwise gets. USE now checks interpreter_enabled first and refuses with a retry message instead. Also includes the amd64/aarch64/riscv64 acceptance boot logs and DoE CSVs from this session. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXieurDfDSsDFdnSyusuWo
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d5722986b2
commit
662ef44e59
+69
@@ -2035,3 +2035,72 @@ FORTH-79/83 personality and has been individually verified standalone. Not re-ru
|
||||
3-arch acceptance pass on its own -- this is a data-only change to one thumbdrive image, no
|
||||
kernel/capsule code touched, and amd64's own live verification above already exercises the same
|
||||
code paths (§XI.4/§XI.5) the last 3-arch pass (§XI.5, commit `b301317`) already accepted.
|
||||
|
||||
## XII. Standard-dictionary cross-ISA exerciser campaign — two real bugs found live and CLOSED,
|
||||
2026-09-10
|
||||
|
||||
Goal of the session: write one FORTH-79-standard-only exerciser program, run it identically
|
||||
against every identity (`zuse` plus all 8 restricted identities) on all three architectures, and
|
||||
diff the results for cross-ISA parity. Getting the mechanism working at all surfaced two real
|
||||
bugs, both fixed here; the actual 27-leg campaign (3 arch × 9 identity) is what resumes next.
|
||||
|
||||
### XII.1 — `EXEC`/`LOAD` gap: a locked identity had no standard-compliant way to load capsule
|
||||
source — CLOSED
|
||||
|
||||
`EXEC` (the kernel's named-capsule loader) was correctly found to be absent from
|
||||
`ACL-STD79-LIST` (`capsules/acl-std79.4th`) -- not itself a bug, `EXEC` is kernel-specific, not a
|
||||
FORTH-79 standard word. The real gap: `BLOCK`/`LOAD`/`THRU` (genuine standard words) *are* on the
|
||||
allowlist, and `capsule_exec_payload()` genuinely does commit each capsule block's content to real
|
||||
ramdrive storage (`write_ramdrive_block()`) before executing it -- so `LOAD` should have been a
|
||||
legitimate standard-compliant fallback. It wasn't: `capsule_exec_init()` (what `EXEC` actually
|
||||
calls, `mama_forth_words.c:1383`) followed `capsule_exec_payload()` with an unconditional
|
||||
`capsule_clear_blocks()`, zeroing every block the capsule had just used before `EXEC` even
|
||||
returned. The window where a capsule's content was actually present in block storage was entirely
|
||||
inside one synchronous `EXEC` call -- nothing external, including a separately-running locked
|
||||
identity's own session, could ever reach it with `LOAD` afterward. Confirmed by reading
|
||||
`capsule_loader.c` directly, not inferred.
|
||||
|
||||
**Fix:** removed the `capsule_clear_blocks()` call from `capsule_exec_init()` (`capsule_loader.c`).
|
||||
Block content written by `EXEC` now persists in ramdrive storage exactly like any other
|
||||
Standard-compliant `BLOCK`/`BUFFER`/`UPDATE` write would, until something explicitly overwrites or
|
||||
blanks it. The other caller of `capsule_clear_blocks()` -- `kernel_main.c`'s own explicit call
|
||||
right after Mama's init.4th birth, to free that specific block range for later interactive
|
||||
block-editor use -- is untouched; that one was already an explicit, separate, documented choice by
|
||||
its own caller, not something `capsule_exec_init()` did on every caller's behalf. Verified:
|
||||
`capsule_birth_mama()` calls `vm_exec_fn` directly (not `capsule_exec_init()`), so this fix has no
|
||||
effect on Mama's own boot path.
|
||||
|
||||
### XII.2 — `USE` into a WIREBIND identity before its interpreter is enabled panics the whole
|
||||
machine — CLOSED
|
||||
|
||||
Found live: attaching identity `03` via QMP hotplug, then immediately sending
|
||||
`S" 03" USE` the moment the log printed `WIREBIND: 03 attached and ready -- USE it to begin`,
|
||||
produced not an ACL fault but a full kernel panic --
|
||||
`[StarKernel HAL] PANIC: interpreter invoked before bootstrap completion` -- and the machine
|
||||
halted completely (`System halted.`, QEMU process left spinning uselessly). Root cause: a WIREBIND
|
||||
identity's VM starts with `interpreter_enabled = 0` (`vm_bootstrap.c:162`) and only gets
|
||||
`vm_enable_interpreter()` called as a later, separate step of the same birth sequence. The
|
||||
"attached and ready" message prints as soon as the VM is registered, before that later step is
|
||||
guaranteed to have run. `mama_word_use()` (`USE`) checked the target for dead/stillborn state but
|
||||
never checked interpreter readiness before redirecting the whole console's input to it -- the very
|
||||
next line typed would hit `vm_assert_interpreter_enabled()` inside `vm_interpret()` and call
|
||||
`host->panic()`, which is a hard, unrecoverable halt, not the per-session-recoverable ACL-fault
|
||||
path a redirected VM otherwise gets (§XI.3's fix). This is a real race independent of automation
|
||||
speed: a human typing `USE` right after seeing "ready" hits it exactly the same way.
|
||||
|
||||
**Fix:** `mama_word_use()` (`mama_forth_words.c`) now checks `((VM *)entry.vm_ptr)->interpreter_
|
||||
enabled` before redirecting, refusing with `USE: <name> not ready yet -- still bootstrapping, try
|
||||
again` instead of performing the redirect. The caller just retries a moment later. Did not touch
|
||||
the birth sequence itself (i.e., did not try to make the "attached and ready" message wait for
|
||||
`vm_enable_interpreter()` to actually run first) -- narrower, lower-risk fix at the point of actual
|
||||
failure.
|
||||
|
||||
**Both fixes verified:** amd64 rebuild clean, zero new warnings.
|
||||
|
||||
**Status:** exerciser campaign resuming with the fixed build. The 24-case exerciser itself (see
|
||||
scratchpad `std79-exerciser.fth`, not yet committed -- FORTH-79 standard words only, biased toward
|
||||
mixed/double-precision arithmetic and shift/negate boundary cases per cross-ISA risk) had already
|
||||
produced one interesting, unconfirmed data point before the panic: `-123 456 M*` printed
|
||||
`DOUBLE-OVERFLOW` via `D.` on amd64, identically for both `zuse` and `rajames` -- worth checking
|
||||
against the other two architectures once the campaign completes; not yet root-caused or reported
|
||||
as a bug on its own.
|
||||
|
||||
Reference in New Issue
Block a user