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/memory.rs | 120 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 40 deletions(-) (limited to 'rsnix/src/memory.rs') diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs index e0f0142..f16f943 100644 --- a/rsnix/src/memory.rs +++ b/rsnix/src/memory.rs @@ -480,47 +480,84 @@ fn heap_guard_report(ptr: usize, rsp: usize, size: usize, align: usize) -> ! { w.len() }; - // Words around the block header — the corruption lives in the - // header's size/free slots or the payload. Only when the addresses - // are inside the mapped heap (reading a garbage pointer would fault - // mid-report). Four words per line: the fault band is ~110 chars - // wide, so one long line would truncate under hand-copy. + // Candidate block bases for this ptr (payload sits at block+24 for + // align-1 allocs, block+32 for align-16) with their size/free + // fields, plus a longer raw window around ptr so the next crash + // shows the header region and neighbours, not just the payload. let mut b4 = [0u8; 96]; let mut b4b = [0u8; 96]; - let (n4, n4b) = { - let focus = if block >= hs && block < he { block } else { ptr }; - if focus >= hs + 8 && focus < he { - let lo = (focus - 16).max(hs); - let hi = (focus + 40).min(he - 8); - let mut w = crate::strbuf::FmtBuf::new(&mut b4); - let _ = fmt::write(&mut w, core::format_args!("mem:")); - let mut a = lo & !7; - let mut n = 0; - while a <= hi && n < 4 { - let _ = fmt::write( - &mut w, - core::format_args!(" {:x}={:#x}", a, unsafe { *(a as *const usize) }), - ); - a += 8; - n += 1; - } - let mut w2 = crate::strbuf::FmtBuf::new(&mut b4b); - let _ = fmt::write(&mut w2, core::format_args!("mem2:")); - let mut n = 0; - while a <= hi && n < 4 { - let _ = fmt::write( - &mut w2, - core::format_args!(" {:x}={:#x}", a, unsafe { *(a as *const usize) }), - ); - a += 8; - n += 1; - } - (w.len(), w2.len()) - } else { - let mut w = crate::strbuf::FmtBuf::new(&mut b4); - let _ = fmt::write(&mut w, core::format_args!("mem: out of heap — no dump")); - (w.len(), 0) + let mut b4c = [0u8; 96]; + let mut b4d = [0u8; 96]; + let focus = if block >= hs && block < he { block } else { ptr }; + let mut a = (focus.wrapping_sub(48)).max(hs) & !7; + let (mut n4, mut n4b, mut n4c, mut n4d) = (0usize, 0usize, 0usize, 0usize); + if focus >= hs + 8 && focus < he { + let mut w = crate::strbuf::FmtBuf::new(&mut b4); + let _ = fmt::write(&mut w, core::format_args!("mem:")); + for _ in 0..4 { + let _ = fmt::write( + &mut w, + core::format_args!(" {:x}={:#x}", a, unsafe { *(a as *const usize) }), + ); + a += 8; + } + n4 = w.len(); + let mut w = crate::strbuf::FmtBuf::new(&mut b4b); + let _ = fmt::write(&mut w, core::format_args!("mem2:")); + for _ in 0..4 { + let _ = fmt::write( + &mut w, + core::format_args!(" {:x}={:#x}", a, unsafe { *(a as *const usize) }), + ); + a += 8; } + n4b = w.len(); + let mut w = crate::strbuf::FmtBuf::new(&mut b4c); + let _ = fmt::write(&mut w, core::format_args!("mem3:")); + for _ in 0..4 { + let _ = fmt::write( + &mut w, + core::format_args!(" {:x}={:#x}", a, unsafe { *(a as *const usize) }), + ); + a += 8; + } + n4c = w.len(); + let mut w = crate::strbuf::FmtBuf::new(&mut b4d); + let _ = fmt::write(&mut w, core::format_args!("mem4:")); + for _ in 0..4 { + let _ = fmt::write( + &mut w, + core::format_args!(" {:x}={:#x}", a, unsafe { *(a as *const usize) }), + ); + a += 8; + } + n4d = w.len(); + } else { + let mut w = crate::strbuf::FmtBuf::new(&mut b4); + let _ = fmt::write(&mut w, core::format_args!("mem: out of heap — no dump")); + n4 = w.len(); + }; + // Explicit candidate-block header fields (size/free at +0/+8). + let mut b4e = [0u8; 96]; + let ne = if ptr >= hs + 24 && ptr <= he { + let hb = ptr - 24; + let hb2 = ptr - 32; + let mut w = crate::strbuf::FmtBuf::new(&mut b4e); + let _ = fmt::write( + &mut w, + core::format_args!( + "hdr: b={:#x} s={:#x} f={:#x} b16={:#x} s={:#x} f={:#x}", + hb, + unsafe { *(hb as *const usize) }, + unsafe { *((hb + 8) as *const usize) }, + hb2, + unsafe { *(hb2 as *const usize) }, + unsafe { *((hb2 + 8) as *const usize) }, + ), + ); + w.len() + } else { + 0 }; // Live return-address chain on the stack above our rsp (dealloc ← @@ -563,15 +600,18 @@ fn heap_guard_report(ptr: usize, rsp: usize, size: usize, align: usize) -> ! { let l3b = core::str::from_utf8(&b3b[..n3b]).unwrap_or(""); let l4 = core::str::from_utf8(&b4[..n4]).unwrap_or(""); let l4b = if n4b > 0 { core::str::from_utf8(&b4b[..n4b]).unwrap_or("") } else { "" }; + let l4c = if n4c > 0 { core::str::from_utf8(&b4c[..n4c]).unwrap_or("") } else { "" }; + let l4d = if n4d > 0 { core::str::from_utf8(&b4d[..n4d]).unwrap_or("") } else { "" }; + let l4e = if ne > 0 { core::str::from_utf8(&b4e[..ne]).unwrap_or("") } else { "" }; let l5 = core::str::from_utf8(&b5[..n5]).unwrap_or(""); let l6 = core::str::from_utf8(&b6[..n6]).unwrap_or(""); let l7 = core::str::from_utf8(&b7[..n7]).unwrap_or(""); let l8 = core::str::from_utf8(&b8[..n8]).unwrap_or(""); - for l in [l2, l3, l3b, l4, l4b, l5, l6, l7, l8] { + for l in [l2, l3, l3b, l4, l4b, l4c, l4d, l4e, l5, l6, l7, l8] { crate::serial::write_raw(l); crate::serial::write_raw("\r\n"); } - let lines = [l1, l2, l3, l3b, l4, l4b, l5, l6, l7, l8]; + let lines = [l1, l2, l3, l3b, l4, l4b, l4c, l4d, l4e, l5, l6, l7, l8]; crate::gop::dump_lines(&lines); crate::fs::write_crash_log(&lines); crate::interrupts::halt() -- cgit v1.2.3