From 834b931d068a9a76e2c2a85267f24a22e93276cf Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 3 Aug 2026 00:21:52 +0200 Subject: v0.5.7: guard dumps block-header math + 16-word window; vt content verify; shadow marker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The klog -t 2 crash drops a 126-byte String (the vt verify klog line) whose data ptr 0x40444970 points into the first-heap-block region whose content is the firmware 0x00AAAAAA scrub — a stale pointer, not a real allocation (back-pointer slot never written). Upgrades so the next real-hardware crash shows the full picture: - guard: explicit candidate block bases (b=ptr-24 / b16=ptr-32) with their size/free fields, plus a 16-word window (mem..mem4) from ptr-0x30 instead of the old 8 words - vt::debug_verify: content probe of the cells grid (must be all-BLANK at shell entry) — catches a stale in-heap cells pointer that passes the range checks - gop: on-screen marker for shadow carved vs NO-SHADOW fallback (the scrub content at the crash ptr suggests the shadow was rejected and its block stayed free + firmware-scrubbed) --- rsnix/src/vt.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'rsnix/src/vt.rs') diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs index 2d8ece6..2906258 100644 --- a/rsnix/src/vt.rs +++ b/rsnix/src/vt.rs @@ -172,13 +172,40 @@ pub fn debug_verify() { p >= hs && p + bytes <= he }) .unwrap_or(false); - if c.len() != total || r.len() != total || !heap_ok { + // Content check: at shell entry nothing has been printed yet, so + // every cell must still be BLANK (all-zero). A stale cells data + // pointer that happens to be in-heap still passes the range + // checks (len/cap look fine) but its "cells" read back as the + // underlying memory's leftover fill — the OptiPlex shows the + // firmware 0x00AAAAAA scrub there. This catches that. + let mut content_ok = true; + if heap_ok && c.len() == total && total > 0 { + let mut i = 0usize; + // Sample the first cell, the last cell, and a few interior + // cells — reading the whole grid here would be ~60 KiB of + // checks at every boot for no real benefit. + let probes = [0usize, total / 3, (2 * total) / 3, total - 1]; + for &p in probes.iter() { + if i >= probes.len() { + break; + } + i += 1; + let cell = *c.as_ptr().add(p); + let raw = cell.ch as u32 | ((cell.fg as u32) << 16) | ((cell.bg as u32) << 24); + if raw != 0 { + content_ok = false; + break; + } + } + } + if c.len() != total || r.len() != total || !heap_ok || !content_ok { msg("verify: FAILED — cells/rendered not sane at shell entry"); crate::gop::boot_marker(&alloc::format!( - "vt: cells {:#x} {}/{} FAILED", + "vt: cells {:#x} {}/{} {}", c.as_ptr() as usize, c.len(), - total + total, + if content_ok { "range" } else { "CONTENT-GARBAGE" } )); } else { msg("verify: ok"); -- cgit v1.2.3