Stage K-1: real kernel realloc; word-metrics defects closed (FABRIC-3.10.8 §4.1)
- Kernel sf_realloc() is a real realloc (copy min(old,new) via new kmalloc_usable_size(), free old, NULL-on-0 frees). It allocated fresh and nothing else: every growth leaked, and vm_state_push()'s call-state stack lost every saved state past depth 8 (found here). - Shim realloc() copies min(old,new) (over-read when growing). - Defect 9: FC bucket growth no longer leaks or patches a copy; no sf_xrealloc() (freed a block the index still held on failure). - Defect 5: heat snapshot heap-sized (was heats[1024], truncating). - Defect 6: word refused whole when its metrics can't be allocated. - Defect 7: vm_cleanup() (both) frees metrics' inner arrays. - Defect 8: most-likely-next kept incrementally; no full id scan. - Probe (removed): realloc keeps contents, heap returns exactly; call stack depth 20 intact; all three ISAs. Churn criterion NOT met: ~7 KB retained per churned VM (quota slots/word rows -- K-4 re-measures); a post-churn CONSOLE-CMD refusal attributed to the quota leak, K-4 retests. - Standard sequence on amd64/aarch64/riscv64: hashes, G, ledger unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ef849906d9
commit
27c430e0ca
@@ -431,3 +431,51 @@ named here before it runs. No DoE.
|
||||
| **K-7** | the `lfs/` rewrite | The hosted `Makefile` no longer copies the binary into `lfs/`. | After `make`, `git status` shows no change under `lfs/`. |
|
||||
|
||||
MC-1 follows once these are closed.
|
||||
|
||||
### 4.1 K-1 — the allocator and word metrics (2026-09-26)
|
||||
|
||||
**Change.**
|
||||
- **The kernel `sf_realloc()` is a real realloc.** It allocates the new block, copies `min(old, new)` bytes, frees the old block, and on size 0 frees and returns NULL. The old size comes from a new `kmalloc_usable_size()`; on failure the old block is untouched.
|
||||
- It used to allocate fresh and do nothing else, while its callers assumed standard realloc.
|
||||
- **Found while closing defect 9:** `vm_state_push()`'s call-state stack (BIRTH, VM-EXEC and START nesting) grows through `sf_realloc()`, so past depth 8 every saved state was lost, and every growth leaked.
|
||||
- **Shim `realloc()`** copies `min(old, new)`; it used to copy `size` bytes, over-reading the old block whenever it grew.
|
||||
- **Defect 9:** the dictionary-index bucket growth drops its kernel-only copy patch, which would now read freed memory, and stops leaking the old block. It also calls `sf_realloc()` directly instead of `sf_xrealloc()`, which freed the old block on failure while the index still pointed at it. `sf_xrealloc()` is gone.
|
||||
- **Defect 5:** the heat-percentile snapshot is heap-sized to the dictionary, allocated per call (was `heats[DICTIONARY_SIZE]`, cut at 1024 words). An allocation failure is logged and the previous thresholds stand.
|
||||
- **Defect 6:** a word whose transition metrics can't be allocated is refused whole: `vm->error` set, logged at ERROR, counted with the word-id refusals. It used to be defined anyway, with a WARN.
|
||||
- **Defect 7:** both `vm_cleanup()`s call `transition_metrics_cleanup()` before freeing each word's metrics, so the inner arrays are freed.
|
||||
- **Defect 8:** `transition_metrics_record()` keeps the most-likely-next word current (highest count, lowest id on a tie), and `transition_metrics_update_cache()` only refreshes its probability instead of scanning every id.
|
||||
- Compiled out of the kernel today (`ENABLE_PIPELINING` off).
|
||||
- One by-construction difference is documented at the function: the scan compared floored Q48.16 probabilities.
|
||||
- Also fixed: a NULL dereference in that function's guard.
|
||||
|
||||
**Probe** (temporary, removed before commit). A `K1-PROBE` word:
|
||||
1. `sf_malloc(64)` with a pattern, `sf_realloc` to 4096 then to 32, checking the pattern each time, then free, reading heap used bytes before and after;
|
||||
2. a scratch VM's call-state stack pushed to depth 20 and popped, checking every saved field;
|
||||
3. heap used bytes.
|
||||
|
||||
| ISA | log | realloc grow / shrink | heap used before = after | call-state depth 20 |
|
||||
|---|---|---|---|---|
|
||||
| amd64 | `logs/20260926-011757` | kept / kept | yes (3 readings) | intact, capacity 32 |
|
||||
| aarch64 | `logs/20260926-014005` | kept / kept | yes | intact, capacity 32 |
|
||||
| riscv64 | `logs/20260926-014626` | kept / kept | yes | intact, capacity 32 |
|
||||
|
||||
**The churn half of the named evidence is not met.** On amd64 the probe ran `churn.sh` (28 worker births, jobs and KILLs) twice, with the probe word before, between and after:
|
||||
- heap used: 28,871,243 → 29,196,203 (+324,960) → 29,397,899 (+201,696);
|
||||
- so about 7 KB is still retained per churned VM.
|
||||
- Most likely cause: the per-VM state K-4 releases. A dead VM keeps its quota slot, including its Stadium word row (up to about 16 KB at a 1024-id row). Registry nodes are kept by design. K-4 re-measures this.
|
||||
|
||||
In the same run, after the second churn, rajames's `1 2 + .` was **refused by kernel-Hermes** ("refused CONSOLE-CMD-EVENT send").
|
||||
- Most likely cause: the quota leak. Every KILL strands its slot's cells, and each birth halves the best donor, so after 56 churned VMs the newborn console VM's quota can't admit a message cell.
|
||||
- K-1 doesn't touch Stadium or Hermes. **K-4's probe re-runs this double churn followed by `1 2 + .`**, which is the direct test.
|
||||
- The clean acceptance runs below have no churn, and CONSOLE-CMD works in all of them.
|
||||
|
||||
**Standard sequence** (clean build, with the probe reverted; the tree is byte-identical to the saved stage diff; the hosted `make` builds).
|
||||
|
||||
| ISA | log | O-A (G, PREC, LOAD) | M7.1a hash | MINT / WIREBIND / USE / `1 2 + .` | idle growth | UNKNOWN / faults |
|
||||
|---|---|---|---|---|---|---|
|
||||
| amd64 | `logs/20260926-015235` | A=40 B=40, HHH, ok | `0x99b01134c3d3049c` | all ok, `3` | 0 B / 20 s | 0 / 0 |
|
||||
| aarch64 | `logs/20260926-020511` | A=40 B=40, HHH, ok | `0x99b01134c3d3049c` | all ok, `3` | 0 B / 20 s | 0 / 0 |
|
||||
| riscv64 | `logs/20260926-021813` | A=40 B=40, HHH, ok | `0x99b01134c3d3049c` | all ok, `3` | 0 B / 20 s | 0 / 0 |
|
||||
|
||||
- The `dict_hash` set, the G string and the ledger line are unchanged.
|
||||
- **K-1 closes §8 defects 5–9 and the `sf_realloc()`/call-state-stack bug.** Its churn-leak criterion carries into K-4.
|
||||
|
||||
Reference in New Issue
Block a user