diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-02 21:47:18 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-02 21:47:18 +0200 |
| commit | 0187b802113a10a9ee99af48b811cd332c660a13 (patch) | |
| tree | b0873f7b2dcf6be1c575c8fe1919a72f041bba49 /shell/src | |
| parent | v0.5.6: fault dumps carry kernel image base + stack backtrace (diff) | |
| download | rs-dos-0187b802113a10a9ee99af48b811cd332c660a13.tar.gz rs-dos-0187b802113a10a9ee99af48b811cd332c660a13.zip | |
v0.5.7: allocator corruption guard + full register dump for real-hardware repro
The OptiPlex #GP (vec=13 in __rust_dealloc) frees a garbage pointer: the
back-pointer at [ptr-8] is clobbered by the time the shell drops its
Parsed struct. A blind store to the bogus block header was an opaque
#GP — now it is a readable report:
- dealloc validates the back-pointer (in-heap block, sane size, in-use)
before trusting it; on failure it prints ptr/block/heap range, the
memory around the block header, and the live stack chain, writes the
crash band + crash.log, and halts (memory.rs: heap_guard_report).
- fault dumps now carry the full register set (rax..rdi, rbx, r8..r15)
so the next repro shows the exact freed ptr and clobbered value.
- new 'corrupt' shell hook deliberately clobbers a live block's
back-pointer to prove the guard fires (test-fault-style halt).
Verified: test-msg/test-disk/test-fault pass; corrupt hook reports
ptr=.. block=0xdeedbeef... with mem dump instead of #GP. rs-dos.img
rebuilt with the release kernel.
Diffstat (limited to '')
| -rw-r--r-- | shell/src/lib.rs | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/shell/src/lib.rs b/shell/src/lib.rs index a32d259..175a2c7 100644 --- a/shell/src/lib.rs +++ b/shell/src/lib.rs | |||
| @@ -740,6 +740,7 @@ write `{} <path> TIL <marker>`", | |||
| 740 | "kill" => cmd_kill(&parsed), | 740 | "kill" => cmd_kill(&parsed), |
| 741 | "demo" => cmd_demo(&parsed), | 741 | "demo" => cmd_demo(&parsed), |
| 742 | "fault" => cmd_fault(), | 742 | "fault" => cmd_fault(), |
| 743 | "corrupt" => cmd_corrupt(), | ||
| 743 | "crashlog" => cmd_crashlog(), | 744 | "crashlog" => cmd_crashlog(), |
| 744 | "stall" => cmd_stall(&parsed), | 745 | "stall" => cmd_stall(&parsed), |
| 745 | _ => term_err(&alloc::format!("unknown command: {}", cmd)), | 746 | _ => term_err(&alloc::format!("unknown command: {}", cmd)), |
| @@ -839,6 +840,21 @@ fn cmd_fault() { | |||
| 839 | } | 840 | } |
| 840 | } | 841 | } |
| 841 | 842 | ||
| 843 | /// Deliberately clobber a live heap block's back-pointer, then free it — | ||
| 844 | /// test hook that proves the allocator's corruption guard fires with a | ||
| 845 | /// readable report (instead of a #GP inside `__rust_dealloc`). The | ||
| 846 | /// system stops; the log must show `!!! heap corruption in dealloc`. | ||
| 847 | fn cmd_corrupt() { | ||
| 848 | term_println("corrupt: clobbering a live block's back-pointer..."); | ||
| 849 | let s = String::from("hello heap guard"); | ||
| 850 | let ptr = s.as_ptr() as usize; | ||
| 851 | unsafe { | ||
| 852 | *((ptr - 8) as *mut usize) = 0xdeed_beef_deed_beefusize; | ||
| 853 | } | ||
| 854 | drop(s); | ||
| 855 | term_println("corrupt: guard did NOT fire (unexpected)"); | ||
| 856 | } | ||
| 857 | |||
| 842 | /// Debug hook: run the crash-log FAT write from the *shell* context (not | 858 | /// Debug hook: run the crash-log FAT write from the *shell* context (not |
| 843 | /// the fault ISR) to compare behaviour. | 859 | /// the fault ISR) to compare behaviour. |
| 844 | fn cmd_crashlog() { | 860 | fn cmd_crashlog() { |
