Stage D batch 2: fix silent error sites in log_words.c, resolve the flagged category-iii special case (FABRIC-3.md §XXXII.6)
Build / build-amd64-iso (push) Waiting to run
Build / build-aarch64-iso (push) Waiting to run
Build / build-riscv64-img (push) Waiting to run

log_word_set_level(), log_do_emit(), and log_emit_string() (7 sites
total) now log a diagnostic via log_message(LOG_ERROR, ...) before
setting vm->error, matching this file's own already-correct
log_str_emit() sibling and defer_words.c's gold-standard pattern.

log_word_append_raw() (backing (LOG-APPEND-RAW), 3 sites) resolved
differently per §XXXII.3's own triage note: its doc comment forbids
log_message() here (recursion into the log ring it writes to), but the
word can also be invoked by hand at the console -- console_println()
carries no such recursion risk and matches Stage B's policy for a
manual interactive invocation. Added the console.h include this
required.

Three-arch clean qemu acceptance passed.

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 16:53:18 -04:00
co-authored by Claude Sonnet 5
parent 5417ffb2bf
commit 1a8c0e4fcf
10 changed files with 27224 additions and 11 deletions
+23
View File
@@ -4544,3 +4544,26 @@ genuinely malformed message or an out-of-bounds array reference to trigger) -- t
mechanical (add a `log_message()` call, no logic change) and low-risk, matching this project's
own precedent for this class of change.
**Batch 2 -- DONE, 2026-09-15: `log_words.c` (10 silent sites + the 1 flagged category-iii
special case).** `log_word_set_level()`, `log_do_emit()` (2 sites), `log_emit_string()` (4
sites) all gained a `log_message(LOG_ERROR, ...)` diagnostic before their existing
`vm->error = 1`, matching this same file's own already-correct `log_str_emit()` sibling and
`defer_words.c`'s gold-standard pattern -- straightforward, no special handling needed.
**The category-iii special case, resolved rather than left flagged.** §XXXII.3 identified
`log_word_append_raw()` (backing `(LOG-APPEND-RAW)`) as needing a different mechanism: its own
doc comment forbids `log_message()` on this path (recursion into the log ring it writes to,
per `log_region.c`'s own doc comment), yet the word can also be invoked "by hand at the console
for a smoke test" per that same comment -- meaning a silent failure there is exactly USE's own
problem, just for a different word. Resolved: `console_println()` carries no recursion risk (a
direct console/framebuffer write, not routed through the log system at all) and correctly
matches Stage B's own policy for a manual interactive invocation. Added
`#include "starkernel/console.h"` (not previously included) and three diagnostics
(stack underflow, negative message length, address out of range) to `log_word_append_raw()`'s
three guards.
**Verified:** three-architecture `clean qemu` acceptance (amd64/aarch64/riscv64) passed, standard
regression unaffected. Not separately live-fired against any of the 11 sites' specific failure
conditions -- same reasoning as batch 1, all fixes are mechanical diagnostic additions with no
logic change.
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-09-15T20:13:26Z -->
<!-- Generated by mkcapsule --manifest 2026-09-15T20:43:41Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+56 -10
View File
@@ -18,6 +18,7 @@
#include "starkernel/log_region.h"
#include "starkernel/log_attrib.h" /* vm_log_attributed_vm() */
#include "starkernel/capsule_birth.h" /* capsule_vm_registry_get, VMRegistryEntry */
#include "starkernel/console.h" /* console_println() -- (LOG-APPEND-RAW) diagnostics */
#include <string.h> /* strlen */
#endif
@@ -45,7 +46,11 @@ static void log_word_debug(VM *vm) { vm_push(vm, (cell_t)LOG_DEBUG); }
*/
static void log_word_set_level(VM *vm)
{
if (vm->dsp < 0) { vm->error = 1; return; }
if (vm->dsp < 0) {
log_message(LOG_ERROR, "LOG-LEVEL!: stack underflow");
vm->error = 1;
return;
}
cell_t n = vm_pop(vm);
if (n < (cell_t)LOG_ERROR) n = (cell_t)LOG_ERROR;
if (n > (cell_t)LOG_DEBUG) n = (cell_t)LOG_DEBUG;
@@ -75,9 +80,17 @@ static void log_word_get_level(VM *vm)
static void log_do_emit(VM *vm, LogLevel level)
{
if (vm->rsp < 0) { vm->error = 1; return; }
if (vm->rsp < 0) {
log_message(LOG_ERROR, "(do-log-*): return-stack underflow");
vm->error = 1;
return;
}
uint8_t *data = (uint8_t *)(uintptr_t)vm->return_stack[vm->rsp];
if (!data) { vm->error = 1; return; }
if (!data) {
log_message(LOG_ERROR, "(do-log-*): NULL inline-string pointer");
vm->error = 1;
return;
}
uint8_t n = data[0];
/* advance IP before emitting so re-entrant calls see correct state */
size_t skip = 1 + (size_t)n;
@@ -106,12 +119,20 @@ static void log_emit_string(VM *vm, LogLevel level,
size_t pos = vm->input_pos;
size_t end = vm->input_length;
if (!src || pos > end) { vm->error = 1; return; }
if (!src || pos > end) {
log_message(LOG_ERROR, "LOG-*\": no input buffer");
vm->error = 1;
return;
}
if (pos < end && src[pos] == ' ') pos++;
size_t start = pos;
while (pos < end && src[pos] != '"') pos++;
if (pos >= end) { vm->error = 1; return; }
if (pos >= end) {
log_message(LOG_ERROR, "LOG-*\": unterminated string literal");
vm->error = 1;
return;
}
size_t n = pos - start;
if (n > 255) n = 255;
@@ -124,13 +145,21 @@ static void log_emit_string(VM *vm, LogLevel level,
/* Compilation: emit runtime word then inline [len][chars][pad] */
DictEntry *rt = vm_find_word(vm, rt_name, (size_t)rt_nlen);
if (!rt) { vm->error = 1; return; }
if (!rt) {
log_message(LOG_ERROR, "LOG-*\": runtime word '%.*s' not found", rt_nlen, rt_name);
vm->error = 1;
return;
}
vm_compile_word(vm, rt);
size_t skip = 1 + n;
size_t padded = (skip + (sizeof(cell_t) - 1)) & ~(sizeof(cell_t) - 1);
uint8_t *raw = (uint8_t *)vm_allot(vm, padded);
if (!raw) { vm->error = 1; return; }
if (!raw) {
log_message(LOG_ERROR, "LOG-*\": vm_allot failed");
vm->error = 1;
return;
}
raw[0] = (uint8_t)n;
for (size_t i = 0; i < n; i++) raw[1 + i] = (uint8_t)src[start + i];
for (size_t i = 1 + n; i < padded; i++) raw[i] = 0;
@@ -214,14 +243,31 @@ static void log_word_debug_str(VM *vm) { log_str_emit(vm, LOG_DEBUG); }
#ifdef __STARKERNEL__
static void log_word_append_raw(VM *vm)
{
if (vm->dsp < 3) { vm->error = 1; return; }
/* Diagnostics here go via console_println(), not log_message() -- this
* function's own doc comment above forbids log_message() (recursion
* into the log ring it writes to); console_println() carries no such
* risk and covers the "by hand at the console for a smoke test" case
* that same comment names (FABRIC-3.md §XXXII.6). */
if (vm->dsp < 3) {
console_println("(LOG-APPEND-RAW): stack underflow");
vm->error = 1;
return;
}
cell_t msg_u = vm_pop(vm);
cell_t msg_addr = vm_pop(vm);
cell_t timestamp = vm_pop(vm);
cell_t level = vm_pop(vm);
if (msg_u < 0) { vm->error = 1; return; }
if (msg_addr < 0 || (msg_addr + msg_u) > (cell_t)VM_MEMORY_SIZE) { vm->error = 1; return; }
if (msg_u < 0) {
console_println("(LOG-APPEND-RAW): negative message length");
vm->error = 1;
return;
}
if (msg_addr < 0 || (msg_addr + msg_u) > (cell_t)VM_MEMORY_SIZE) {
console_println("(LOG-APPEND-RAW): message address out of range");
vm->error = 1;
return;
}
const char *msg = (const char *)&vm->memory[msg_addr];