From e649a3de7d853bf82a9105a2cb3869c7b8c96108 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 2 Aug 2026 22:46:59 +0200 Subject: v0.5.7: guard report 4-words-per-line — 16 stack words survive band hand-copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OptiPlex repro copies are truncated at the ~110-char band width, so the old single-line 'stk:' (12 words, >200 chars) lost the return chain after a few words. Split mem/stk dumps into 4-words-per-line blocks: mem+mem2 (8 words around the corruption) and stk..stk4 (16 words) — the drop caller chain now survives hand transcription. --- rsnix/src/memory.rs | 84 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 24 deletions(-) (limited to 'rsnix') diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs index 3362d94..ecaf806 100644 --- a/rsnix/src/memory.rs +++ b/rsnix/src/memory.rs @@ -405,58 +405,94 @@ fn heap_guard_report(ptr: usize, rsp: usize) -> ! { // 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). - let mut b4 = [0u8; 216]; - let n4 = { - let mut w = crate::strbuf::FmtBuf::new(&mut b4); + // mid-report). Four words per line: the fault band is ~110 chars + // wide, so one long line would truncate under hand-copy. + 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; - while a <= hi { + 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) } - w.len() }; // Live return-address chain on the stack above our rsp (dealloc ← // drop glue ← shell::run); raw stack words, resolves against the PDB. - let mut b5 = [0u8; 216]; - let n5 = { - let mut w = crate::strbuf::FmtBuf::new(&mut b5); - let _ = fmt::write(&mut w, core::format_args!("stk:")); + // 16 words in 4 lines of 4 — enough to capture the drop caller + // chain on the band even when the copy truncates a line. + let mut b5 = [0u8; 96]; + let mut b6 = [0u8; 96]; + let mut b7 = [0u8; 96]; + let mut b8 = [0u8; 96]; + let (n5, n6, n7, n8) = { let mut a = rsp.wrapping_add(8); - for _ in 0..12 { - let v = unsafe { *(a as *const usize) }; - let _ = fmt::write(&mut w, core::format_args!(" {:x}={:#x}", a, v)); - a += 8; + let bufs: [&mut [u8]; 4] = [&mut b5, &mut b6, &mut b7, &mut b8]; + let mut lens = [0usize; 4]; + for li in 0..4 { + let mut w = crate::strbuf::FmtBuf::new(bufs[li]); + let lbl = match li { + 0 => "", + 1 => "2", + 2 => "3", + _ => "4", + }; + let _ = fmt::write( + &mut w, + core::format_args!("stk{}:", lbl), + ); + for _ in 0..4 { + let v = unsafe { *(a as *const usize) }; + let _ = fmt::write(&mut w, core::format_args!(" {:x}={:#x}", a, v)); + a += 8; + } + lens[li] = w.len(); } - w.len() + (lens[0], lens[1], lens[2], lens[3]) }; let l1 = core::str::from_utf8(&b1[..n1]).unwrap_or("!!!"); let l2 = core::str::from_utf8(&b2[..n2]).unwrap_or(""); let l3 = core::str::from_utf8(&b3[..n3]).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 l5 = core::str::from_utf8(&b5[..n5]).unwrap_or(""); - crate::serial::write_raw(l2); - crate::serial::write_raw("\r\n"); - crate::serial::write_raw(l3); - crate::serial::write_raw("\r\n"); - crate::serial::write_raw(l4); - crate::serial::write_raw("\r\n"); - crate::serial::write_raw(l5); - crate::serial::write_raw("\r\n"); - let lines = [l1, l2, l3, l4, l5]; + 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, l4, l4b, l5, l6, l7, l8] { + crate::serial::write_raw(l); + crate::serial::write_raw("\r\n"); + } + let lines = [l1, l2, l3, l4, l4b, l5, l6, l7, l8]; crate::gop::dump_lines(&lines); crate::fs::write_crash_log(&lines); crate::interrupts::halt() -- cgit v1.2.3