Stage D batch 5: mama_forth_words.c group 3 -- cross-VM execution/dispatch, both flagged special cases resolved (FABRIC-3.md §XXXII.6)
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s

VM-STEP/VM-EXEC/VM-CALL (5 sites) gained console_println() diagnostics
matching their own existing sibling guards.

SWITCH-MARK-WORK and VM-HEAT (3 sites) resolved per §XXXII.3's own
recommendation: dropped vm->error entirely rather than diagnosing it,
matching each function's own doc comment ("must never error or spam
the console" / "does not print/error"). SWITCH-MARK-WORK is the same
function §XXVIII.3 already fixed once for an off-by-one that fired
silently on every MSG-SEND in the system -- the guard now genuinely
cannot repeat that by contract, not just by the threshold being right.
VM-HEAT's guards now push 0 and return, matching its own
always-returns-a-value stack effect.

Three-arch clean qemu acceptance passed. Zuse's own WIREBIND attach
(every boot) drives MSG-SEND -> SWITCH-MARK-WORK, so this batch's most
safety-critical fix is exercised by standard acceptance, not just
compiled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
Robert Allan James
2026-09-15 19:23:12 -04:00
co-authored by Claude Sonnet 5
parent b42c3b195c
commit 8b5300fc4f
10 changed files with 27219 additions and 12 deletions
+54 -11
View File
@@ -680,7 +680,11 @@ static void mama_word_vm_step(VM *vm)
VM *target;
char saved_name[VM_NAME_MAX];
if (vm->dsp < 1) { vm->error = 1; return; }
if (vm->dsp < 1) {
console_println("VM-STEP: expects S\" name\" VM-STEP -- nothing on the stack");
vm->error = 1;
return;
}
u = vm_pop(vm);
caddr = vm_pop(vm);
@@ -692,7 +696,11 @@ static void mama_word_vm_step(VM *vm)
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) { vm->error = 1; return; }
if (!p) {
console_println("VM-STEP: invalid address on the stack");
vm->error = 1;
return;
}
src = (const char *)p;
}
for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i];
@@ -741,7 +749,11 @@ static void mama_word_vm_exec(VM *vm)
VM *target;
char saved_name[VM_NAME_MAX];
if (vm->dsp < 3) { vm->error = 1; return; }
if (vm->dsp < 3) {
console_println("VM-EXEC: expects S\" cmd\" S\" name\" VM-EXEC -- too few items on the stack");
vm->error = 1;
return;
}
/* TOS: vm-name-u, vm-name-caddr, cmd-u, cmd-caddr */
vm_u = vm_pop(vm);
@@ -760,7 +772,11 @@ static void mama_word_vm_exec(VM *vm)
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)vm_caddr);
if (!p) { vm->error = 1; return; }
if (!p) {
console_println("VM-EXEC: invalid VM-name address on the stack");
vm->error = 1;
return;
}
src = (const char *)p;
}
for (i = 0; i < (uint32_t)vm_u; i++) vm_name[i] = src[i];
@@ -768,7 +784,11 @@ static void mama_word_vm_exec(VM *vm)
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)cmd_caddr);
if (!p) { vm->error = 1; return; }
if (!p) {
console_println("VM-EXEC: invalid command address on the stack");
vm->error = 1;
return;
}
src = (const char *)p;
}
for (i = 0; i < (uint32_t)cmd_u; i++) cmd_buf[i] = src[i];
@@ -823,7 +843,12 @@ static void mama_word_switch_mark_work(VM *vm)
uint32_t i;
VMRegistryEntry entry;
if (vm->dsp < 1) { vm->error = 1; return; }
/* FABRIC-3.md §XXXII.6, 2026-09-15: this guard used to set vm->error on
* underflow, contradicting this function's own doc comment above ("must
* never error or spam the console") -- flagged as a special case in
* §XXXII.3's triage, not just a missing diagnostic. Silently ignored,
* matching every other malformed-input case in this same function. */
if (vm->dsp < 1) return;
u = vm_pop(vm);
caddr = vm_pop(vm);
@@ -860,7 +885,11 @@ static void mama_word_vm_call(VM *vm)
VM *target;
char saved_name[VM_NAME_MAX];
if (vm->dsp < 3) { vm->error = 1; return; }
if (vm->dsp < 3) {
console_println("VM-CALL: expects S\" cmd\" S\" name\" VM-CALL -- too few items on the stack");
vm->error = 1;
return;
}
vm_u = vm_pop(vm);
vm_caddr = vm_pop(vm);
@@ -878,7 +907,11 @@ static void mama_word_vm_call(VM *vm)
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)vm_caddr);
if (!p) { vm->error = 1; return; }
if (!p) {
console_println("VM-CALL: invalid VM-name address on the stack");
vm->error = 1;
return;
}
src = (const char *)p;
}
for (i = 0; i < (uint32_t)vm_u; i++) vm_name[i] = src[i];
@@ -886,7 +919,11 @@ static void mama_word_vm_call(VM *vm)
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)cmd_caddr);
if (!p) { vm->error = 1; return; }
if (!p) {
console_println("VM-CALL: invalid command address on the stack");
vm->error = 1;
return;
}
src = (const char *)p;
}
for (i = 0; i < (uint32_t)cmd_u; i++) cmd_buf[i] = src[i];
@@ -952,7 +989,13 @@ static void mama_word_vm_heat(VM *vm)
const char *src;
VMRegistryEntry entry;
if (vm->dsp < 1) { vm->error = 1; return; }
/* FABRIC-3.md §XXXII.6, 2026-09-15: both guards below used to set
* vm->error, contradicting this function's own doc comment above
* ("does not print/error") -- flagged as a special case in §XXXII.3's
* triage. Push the same 0 the "unknown name" case already returns,
* matching this word's own always-returns-a-value contract, instead
* of erroring. */
if (vm->dsp < 1) { vm_push(vm, 0); return; }
vm_u = vm_pop(vm);
vm_caddr = vm_pop(vm);
@@ -964,7 +1007,7 @@ static void mama_word_vm_heat(VM *vm)
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)vm_caddr);
if (!p) { vm->error = 1; return; }
if (!p) { vm_push(vm, 0); return; }
src = (const char *)p;
}
for (i = 0; i < (uint32_t)vm_u; i++) vm_name[i] = src[i];