diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d82a825..85fae69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +- [#410] Simplify canary - [#405] Also enable merge queue for changelog enforcer - [#404] Switch from bors to merge queue - [#402] Do not panic if locations do not contain the frame +[#410]: https://github.com/knurling-rs/probe-run/pull/410 [#405]: https://github.com/knurling-rs/probe-run/pull/405 [#404]: https://github.com/knurling-rs/probe-run/pull/404 [#402]: https://github.com/knurling-rs/probe-run/pull/402 diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index 1a1ee2cf..f1f920bc 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::PathBuf; use probe_rs::Core; use signal_hook::consts::signal; @@ -27,36 +27,36 @@ impl From<&String> for BacktraceOptions { } } -pub struct Settings<'p> { +pub struct Settings { pub backtrace_limit: u32, pub backtrace: BacktraceOptions, - pub canary_touched: bool, - pub current_dir: &'p Path, + pub current_dir: PathBuf, pub halted_due_to_signal: bool, pub include_addresses: bool, pub shorten_paths: bool, + pub stack_overflow: bool, } -impl<'p> Settings<'p> { +impl Settings { pub fn new( - canary_touched: bool, - current_dir: &'p Path, + current_dir: PathBuf, halted_due_to_signal: bool, opts: &Opts, + stack_overflow: bool, ) -> Self { Self { backtrace_limit: opts.backtrace_limit, backtrace: (&opts.backtrace).into(), - canary_touched, current_dir, halted_due_to_signal, include_addresses: opts.verbose > 0, shorten_paths: opts.shorten_paths, + stack_overflow, } } fn panic_present(&self) -> bool { - self.canary_touched || self.halted_due_to_signal + self.stack_overflow || self.halted_due_to_signal } } @@ -65,11 +65,10 @@ pub fn print( core: &mut Core, elf: &Elf, target_info: &TargetInfo, - settings: &mut Settings<'_>, + settings: &mut Settings, ) -> anyhow::Result { let mut unwind = unwind::target(core, elf, target_info); - - let frames = symbolicate::frames(&unwind.raw_frames, settings.current_dir, elf); + let frames = symbolicate::frames(&unwind.raw_frames, &settings.current_dir, elf); let contains_exception = unwind .raw_frames diff --git a/src/canary.rs b/src/canary.rs index db0429aa..6e568644 100644 --- a/src/canary.rs +++ b/src/canary.rs @@ -2,7 +2,11 @@ use std::time::Instant; use probe_rs::{Core, MemoryInterface, RegisterId}; -use crate::{registers::PC, Elf, TargetInfo, TIMEOUT}; +use crate::{ + registers::PC, + target_info::{StackInfo, TargetInfo}, + Elf, TIMEOUT, +}; /// Canary value const CANARY_U8: u8 = 0xAA; @@ -11,40 +15,46 @@ const CANARY_U32: u32 = u32::from_le_bytes([CANARY_U8, CANARY_U8, CANARY_U8, CAN /// (Location of) the stack canary /// -/// The stack canary is used to detect *potential* stack overflows +/// The stack canary is used to detect *potential* stack overflows and report the +/// amount of stack used. /// -/// The canary is placed in memory as shown in the diagram below: +/// The whole stack is initialized to `CANARY_U8` before the target program is started. /// +/// When the programs ends (due to panic or breakpoint) the size of the canary is checked. If more +/// than 90% is "touched" (bytes != `CANARY_U8`) then that is considered to be a *potential* stack +/// overflow. In any case the amount of used stack is reported. +/// +/// Before execution: /// ``` text -/// +--------+ -> initial_stack_pointer / stack_range.end() +/// +--------+ -> stack_range.end() (initial_stack_pointer) /// | | -/// | stack | (grows downwards) /// | | -/// +--------+ +/// | canary | +/// | | +/// | | +/// +--------+ -> stack_range.start() +/// | static | (variables, fixed size) +/// +--------+ -> lowest RAM address +/// ``` +/// +/// After execution: +/// ``` text +/// +--------+ -> stack_range.end() (initial_stack_pointer) /// | | +/// | stack | (grows downwards) /// | | /// +--------+ /// | canary | /// +--------+ -> stack_range.start() -/// | | /// | static | (variables, fixed size) -/// | | /// +--------+ -> lowest RAM address /// ``` -/// -/// The whole canary is initialized to `CANARY_U8` before the target program is started. -/// The canary size is 10% of the available stack space or 1 KiB, whichever is smallest. -/// -/// When the programs ends (due to panic or breakpoint) the integrity of the canary is checked. If it was -/// "touched" (any of its bytes != `CANARY_U8`) then that is considered to be a *potential* stack -/// overflow. #[derive(Clone, Copy)] pub struct Canary { - address: u32, - size: usize, - stack_available: u32, + addr: u32, data_below_stack: bool, - measure_stack: bool, + size: u32, + size_kb: f64, } impl Canary { @@ -53,142 +63,134 @@ impl Canary { /// Assumes that the target was reset-halted. pub fn install( core: &mut Core, - target_info: &TargetInfo, elf: &Elf, - measure_stack: bool, - ) -> Result, anyhow::Error> { - let stack_info = match &target_info.stack_info { - Some(stack_info) => stack_info, - None => { - log::debug!("couldn't find valid stack range, not placing stack canary"); - return Ok(None); - } + target_info: &TargetInfo, + ) -> anyhow::Result> { + let canary = match Self::prepare(elf, &target_info.stack_info) { + Some(canary) => canary, + None => return Ok(None), }; - if elf.program_uses_heap() { - log::debug!("heap in use, not placing stack canary"); - return Ok(None); - } + let start = Instant::now(); - let stack_start = *stack_info.range.start(); - let stack_available = *stack_info.range.end() - stack_start; + // paint stack + paint_subroutine::execute(core, canary.addr, canary.size)?; - let size = if measure_stack { - // When measuring stack consumption, we have to color the whole stack. - stack_available as usize - } else { - round_up(stack_available / 10, 4) as usize - }; - - log::debug!( - "{stack_available} bytes of stack available ({:#010X} ..= {:#010X}), using {size} byte canary", - stack_info.range.start(), - stack_info.range.end(), - ); - - let size_kb = size as f64 / 1024.0; - if measure_stack { - // Painting 100KB or more takes a few seconds, so provide user feedback. - log::info!("painting {size_kb:.2} KiB of RAM for stack usage estimation"); - } - let start = Instant::now(); - paint_subroutine::execute(core, stack_start, size as u32)?; let seconds = start.elapsed().as_secs_f64(); - log::trace!( - "setting up canary took {seconds:.3}s ({:.2} KiB/s)", - size_kb / seconds - ); + canary.log_time("painting", seconds); - Ok(Some(Canary { - address: stack_start, - size, - stack_available, - data_below_stack: stack_info.data_below_stack, - measure_stack, - })) + Ok(Some(canary)) } - /// Detect if the stack canary was touched. - pub fn touched(self, core: &mut Core, elf: &Elf) -> anyhow::Result { - let size_kb = self.size as f64 / 1024.0; - if self.measure_stack { - log::info!("reading {size_kb:.2} KiB of RAM for stack usage estimation"); - } + /// Measure the stack usage. + /// + /// Returns `true` if a stack overflow is likely. + pub fn measure(self, core: &mut Core, elf: &Elf) -> anyhow::Result { let start = Instant::now(); - let touched_address = measure_subroutine::execute(core, self.address, self.size as u32)?; + + // measure stack usage + let touched_address = measure_subroutine::execute(core, self.addr, self.size)?; + let seconds = start.elapsed().as_secs_f64(); - log::trace!( - "reading canary took {seconds:.3}s ({:.2} KiB/s)", - size_kb / seconds - ); + self.log_time("reading", seconds); let min_stack_usage = match touched_address { Some(touched_address) => { - log::debug!("canary was touched at {touched_address:#010X}"); - Some(elf.vector_table.initial_stack_pointer - touched_address) + log::debug!("stack was touched at {touched_address:#010X}"); + elf.vector_table.initial_stack_pointer - touched_address + } + None => { + log::warn!("stack was not used at all"); + 0 } - None => None, }; - if self.measure_stack { - let min_stack_usage = min_stack_usage.unwrap_or(0); - let used_kb = min_stack_usage as f64 / 1024.0; - let avail_kb = self.stack_available as f64 / 1024.0; - let pct = used_kb / avail_kb * 100.0; - log::info!( - "program has used at least {used_kb:.2}/{avail_kb:.2} KiB ({pct:.1}%) of stack space" - ); + let used_kb = min_stack_usage as f64 / 1024.0; + let pct = used_kb / self.size_kb * 100.0; + let msg = format!( + "program has used at least {used_kb:.2}/{:.2} KiB ({pct:.1}%) of stack space", + self.size_kb + ); - // Don't test for stack overflows if we're measuring stack usage. - Ok(false) + // stack touched? + // + // We consider >90% stack usage a potential stack overflow + if pct > 90.0 { + log::warn!("{}", msg); + if self.data_below_stack { + log::warn!("data segments might be corrupted due to stack overflow"); + } + Ok(true) } else { - match min_stack_usage { - Some(min_stack_usage) => { - let used_kb = min_stack_usage as f64 / 1024.0; - let avail_kb = self.stack_available as f64 / 1024.0; - let pct = used_kb / avail_kb * 100.0; - log::warn!( - "program has used at least {used_kb:.2}/{avail_kb:.2} KiB ({pct:.1}%) of stack space", - ); - - if self.data_below_stack { - log::warn!("data segments might be corrupted due to stack overflow"); - } - - Ok(true) - } - None => { - log::debug!("stack canary intact"); - Ok(false) - } + log::info!("{}", msg); + Ok(false) + } + } + + /// Prepare, but not place the canary. + /// + /// If this succeeds, we have all the information we need in order to place the canary. + fn prepare(elf: &Elf, stack_info: &Option) -> Option { + let stack_info = match stack_info { + Some(stack_info) => stack_info, + None => { + log::debug!("couldn't find valid stack range, not placing stack canary"); + return None; } + }; + + if elf.program_uses_heap() { + log::debug!("heap in use, not placing stack canary"); + return None; } + + let stack_addr = *stack_info.range.start(); + let stack_size = *stack_info.range.end() - stack_addr; + + log::debug!( + "{stack_size} bytes of stack available ({stack_addr:#010X} ..= {:#010X})", + stack_info.range.end(), + ); + + Self::assert_subroutines(stack_addr, stack_size)?; + + Some(Canary { + addr: stack_addr, + data_below_stack: stack_info.data_below_stack, + size: stack_size, + size_kb: stack_size as f64 / 1024.0, + }) } -} -/// Rounds up to the next multiple of `k` that is greater or equal to `n`. -fn round_up(n: u32, k: u32) -> u32 { - match n % k { - 0 => n, - rem => n + k - rem, + fn log_time(&self, action: &str, seconds: f64) { + log::debug!( + "{action} {:.2} KiB of RAM took {seconds:.3}s ({:.2} KiB/s)", + self.size_kb, + self.size_kb / seconds + ) } -} -/// Assert 4-byte-alignment and that subroutine fits inside stack. -macro_rules! assert_subroutine { - ($low_addr:expr, $stack_size:expr, $subroutine_size:expr) => { - assert_eq!($low_addr % 4, 0, "low_addr needs to be 4-byte-aligned"); - assert_eq!($stack_size % 4, 0, "stack_size needs to be 4-byte-aligned"); + /// Assert 4-byte-alignment and that subroutine fits inside stack. + fn assert_subroutines(stack_addr: u32, stack_size: u32) -> Option<()> { + assert_eq!(stack_addr % 4, 0, "low_addr needs to be 4-byte-aligned"); + assert_eq!(stack_size % 4, 0, "stack_size needs to be 4-byte-aligned"); assert_eq!( - $subroutine_size % 4, + paint_subroutine::size() % 4, 0, - "subroutine needs to be 4-byte-aligned" + "paint subroutine needs to be 4-byte-aligned" ); - assert!( - $subroutine_size < $stack_size, - "subroutine does not fit inside stack" + assert_eq!( + measure_subroutine::size() % 4, + 0, + "measure subroutine needs to be 4-byte-aligned" ); - }; + if (stack_size < paint_subroutine::size()) || (stack_size < measure_subroutine::size()) { + log::warn!("subroutines do not fit in stack; not placing stack canary"); + None + } else { + Some(()) + } + } } /// Paint-stack subroutine. @@ -238,7 +240,6 @@ mod paint_subroutine { /// paints the whole memory, except of itself. After the subroutine finishes /// executing we overwrite the subroutine using the probe. pub fn execute(core: &mut Core, low_addr: u32, stack_size: u32) -> Result<(), probe_rs::Error> { - assert_subroutine!(low_addr, stack_size, self::SUBROUTINE.len() as u32); super::execute_subroutine(core, low_addr, stack_size, self::SUBROUTINE)?; self::overwrite_subroutine(core, low_addr)?; Ok(()) @@ -259,6 +260,10 @@ mod paint_subroutine { 0x00, 0xbe, // bkpt 0x0000 0x00, 0xbe, // bkpt 0x0000 (padding instruction) ]; + + pub const fn size() -> u32 { + self::SUBROUTINE.len() as _ + } } /// Measure-stack subroutine. @@ -335,12 +340,9 @@ mod measure_subroutine { low_addr: u32, stack_size: u32, ) -> Result, probe_rs::Error> { - assert_subroutine!(low_addr, stack_size, self::SUBROUTINE.len() as u32); - // use probe to search through the memory the subroutine will be written to - match self::search_with_probe(core, low_addr)? { - addr @ Some(_) => return Ok(addr), // if we find a touched value, return early ... - None => {} // ... otherwise we continue + if let Some(addr) = self::search_with_probe(core, low_addr)? { + return Ok(Some(addr)); // return early, if we find a touched value } super::execute_subroutine(core, low_addr, stack_size, self::SUBROUTINE)?; @@ -375,7 +377,7 @@ mod measure_subroutine { .to_le_bytes() .into_iter() .position(|b| b != CANARY_U8) - .unwrap(); + .expect("some byte has to be touched, if `word_addr != 0`"); Ok(Some(word_addr + offset as u32)) } @@ -392,13 +394,17 @@ mod measure_subroutine { 0x00, 0xbe, // bkpt 0x0000 0x00, 0xbe, // bkpt 0x0000 (padding instruction) ]; + + pub const fn size() -> u32 { + self::SUBROUTINE.len() as _ + } } /// Prepare and run subroutine. Also clean up afterwards. /// /// # How? /// -/// We place the parameters in the registers (see table below), place the subroutien +/// We place the parameters in the registers (see table below), place the subroutine /// in memory, set the program counter to the beginning of the subroutine, execute /// the subroutine and reset the program counter afterwards. /// @@ -440,22 +446,3 @@ fn execute_subroutine( Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - - use rstest::rstest; - - #[rstest] - #[case(2, 4, 4)] - #[case(4, 4, 4)] - #[case(6, 4, 8)] - #[case(8, 4, 8)] - #[case::odd(5, 3, 6)] - #[should_panic] - #[case::div_zero(4, 0, 0)] - fn test_round_up(#[case] n: u32, #[case] k: u32, #[case] res: u32) { - assert_eq!(round_up(n, k), res); - } -} diff --git a/src/cli.rs b/src/cli.rs index dadece14..4ec4c162 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -123,6 +123,10 @@ pub fn handle_arguments() -> anyhow::Result { } }); + if opts.measure_stack { + log::warn!("use of deprecated option `--measure-stack`: Has no effect and will vanish on next breaking release") + } + if opts.version { print_version(); Ok(EXIT_SUCCESS) diff --git a/src/main.rs b/src/main.rs index dc276aee..f7f81e63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,26 +71,26 @@ fn run_target_program(elf_path: &Path, chip_name: &str, opts: &cli::Opts) -> any let target_info = TargetInfo::new(elf, memory_map, probe_target, stack_start)?; // install stack canary - let canary = Canary::install(core, &target_info, elf, opts.measure_stack)?; - if opts.measure_stack && canary.is_none() { - bail!("failed to set up stack measurement"); + let canary = Canary::install(core, elf, &target_info)?; + if canary.is_none() { + log::info!("stack measurement was not set up"); } // run program and print logs until there is an exception start_program(core, elf)?; - let current_dir = &env::current_dir()?; - let halted_due_to_signal = print_logs(core, current_dir, elf, &target_info.memory_map, opts)?; // blocks until exception + let current_dir = env::current_dir()?; + let halted_due_to_signal = print_logs(core, ¤t_dir, elf, &target_info.memory_map, opts)?; // blocks until exception print_separator()?; // analyze stack canary - let canary_touched = canary - .map(|canary| canary.touched(core, elf)) + let stack_overflow = canary + .map(|canary| canary.measure(core, elf)) .transpose()? .unwrap_or(false); // print the backtrace let mut backtrace_settings = - backtrace::Settings::new(canary_touched, current_dir, halted_due_to_signal, opts); + backtrace::Settings::new(current_dir, halted_due_to_signal, opts, stack_overflow); let outcome = backtrace::print(core, elf, &target_info, &mut backtrace_settings)?; // reset the target diff --git a/tests/snapshots/snapshot__case_1_successful_run_has_no_backtrace.snap b/tests/snapshots/snapshot__case_1_successful_run_has_no_backtrace.snap index 5b955dbe..f98a1e13 100644 --- a/tests/snapshots/snapshot__case_1_successful_run_has_no_backtrace.snap +++ b/tests/snapshots/snapshot__case_1_successful_run_has_no_backtrace.snap @@ -1,6 +1,6 @@ --- source: tests/snapshot.rs -assertion_line: 113 +assertion_line: 114 expression: run_result.output --- @@ -9,5 +9,6 @@ expression: run_result.output ──────────────────────────────────────────────────────────────────────────────── Hello, world! ──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO program has used at least 0.16/254.93 KiB (0.1%) of stack space (HOST) INFO device halted without error diff --git a/tests/snapshots/snapshot__case_2_raw_encoding.snap b/tests/snapshots/snapshot__case_2_raw_encoding.snap index 5b955dbe..d6365197 100644 --- a/tests/snapshots/snapshot__case_2_raw_encoding.snap +++ b/tests/snapshots/snapshot__case_2_raw_encoding.snap @@ -1,6 +1,6 @@ --- source: tests/snapshot.rs -assertion_line: 113 +assertion_line: 114 expression: run_result.output --- @@ -9,5 +9,6 @@ expression: run_result.output ──────────────────────────────────────────────────────────────────────────────── Hello, world! ──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO program has used at least 0.12/254.93 KiB (0.0%) of stack space (HOST) INFO device halted without error diff --git a/tests/snapshots/snapshot__case_3_successful_run_can_enforce_backtrace.snap b/tests/snapshots/snapshot__case_3_successful_run_can_enforce_backtrace.snap index 3570b3ef..e7a492ec 100644 --- a/tests/snapshots/snapshot__case_3_successful_run_can_enforce_backtrace.snap +++ b/tests/snapshots/snapshot__case_3_successful_run_can_enforce_backtrace.snap @@ -1,6 +1,6 @@ --- source: tests/snapshot.rs -assertion_line: 113 +assertion_line: 114 expression: run_result.output --- @@ -9,6 +9,7 @@ expression: run_result.output ──────────────────────────────────────────────────────────────────────────────── Hello, world! ──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO program has used at least 0.16/254.93 KiB (0.1%) of stack space stack backtrace: 0: lib::inline::__bkpt at ./asm/inline.rs:14:5 diff --git a/tests/snapshots/snapshot__case_5_panic_is_reported_as_such.snap b/tests/snapshots/snapshot__case_5_panic_is_reported_as_such.snap index fe659bf4..ac045cd7 100644 --- a/tests/snapshots/snapshot__case_5_panic_is_reported_as_such.snap +++ b/tests/snapshots/snapshot__case_5_panic_is_reported_as_such.snap @@ -1,6 +1,6 @@ --- source: tests/snapshot.rs -assertion_line: 113 +assertion_line: 114 expression: run_result.output --- @@ -9,6 +9,7 @@ expression: run_result.output ──────────────────────────────────────────────────────────────────────────────── ERROR panicked at 'explicit panic' ──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO program has used at least 0.16/254.93 KiB (0.1%) of stack space stack backtrace: 0: HardFaultTrampoline diff --git a/tests/snapshots/snapshot__case_6_panic_verbose.snap b/tests/snapshots/snapshot__case_6_panic_verbose.snap index 545c83a0..f306235f 100644 --- a/tests/snapshots/snapshot__case_6_panic_verbose.snap +++ b/tests/snapshots/snapshot__case_6_panic_verbose.snap @@ -1,33 +1,34 @@ --- source: tests/snapshot.rs -assertion_line: 113 +assertion_line: 114 expression: run_result.output --- +(HOST) DEBUG found 1 probes +(HOST) DEBUG opened probe +(HOST) DEBUG started session +(HOST) INFO flashing program (2 pages / 8.00 KiB) +(HOST) DEBUG Erased sector of size 4096 bytes in 122 ms +(HOST) DEBUG Erased sector of size 4096 bytes in 101 ms +(HOST) DEBUG Programmed page of size 4096 bytes in 66 ms +(HOST) DEBUG Programmed page of size 4096 bytes in 67 ms +(HOST) INFO success! (HOST) DEBUG vector table: VectorTable { initial_stack_pointer: 2003fbc0, hard_fault: 17d3 } (HOST) DEBUG RAM region: 0x20000000-0x2003FFFF (HOST) DEBUG section `.data` is in RAM at 0x2003FBC0..=0x2003FBF7 (HOST) DEBUG section `.bss` is in RAM at 0x2003FBF8..=0x2003FBFF (HOST) DEBUG section `.uninit` is in RAM at 0x2003FC00..=0x2003FFFF (HOST) DEBUG valid SP range: 0x20000000..=0x2003FBBC -(HOST) DEBUG found 1 probes -(HOST) DEBUG opened probe -(HOST) DEBUG started session -(HOST) INFO flashing program (2 pages / 8.00 KiB) -(HOST) DEBUG Erased sector of size 4096 bytes in 121 ms -(HOST) DEBUG Erased sector of size 4096 bytes in 99 ms -(HOST) DEBUG Programmed page of size 4096 bytes in 62 ms -(HOST) DEBUG Programmed page of size 4096 bytes in 62 ms -(HOST) INFO success! -(HOST) DEBUG 261052 bytes of stack available (0x20000000 ..= 0x2003FBBC), using 1024 byte canary -(HOST) TRACE setting up canary took 0.020s (51.19 KiB/s) +(HOST) DEBUG 261052 bytes of stack available (0x20000000 ..= 0x2003FBBC) +(HOST) DEBUG painting 254.93 KiB of RAM took 0.031s (8287.09 KiB/s) (HOST) DEBUG starting device (HOST) DEBUG Successfully attached RTT ──────────────────────────────────────────────────────────────────────────────── ERROR panicked at 'explicit panic' ──────────────────────────────────────────────────────────────────────────────── -(HOST) TRACE reading canary took 0.024s (41.48 KiB/s) -(HOST) DEBUG stack canary intact +(HOST) DEBUG reading 254.93 KiB of RAM took 0.048s (5308.39 KiB/s) +(HOST) DEBUG stack was touched at 0x2003FB20 +(HOST) INFO program has used at least 0.16/254.93 KiB (0.1%) of stack space (HOST) TRACE 0x000017d2: found FDE for 0x000017d2 .. 0x000017ea at offset 5672 (HOST) TRACE uwt row for pc 0x000017d2: UnwindTableRow { start_address: 6098, end_address: 6122, saved_args_size: 0, cfa: RegisterAndOffset { register: Register(13), offset: 0 }, registers: RegisterRuleMap { rules: [] } } (HOST) DEBUG LR=0xFFFFFFF9 PC=0x000017D2 diff --git a/tests/snapshots/snapshot__case_7_unsuccessful_run_can_suppress_backtrace.snap b/tests/snapshots/snapshot__case_7_unsuccessful_run_can_suppress_backtrace.snap index d0dcc24f..580c4546 100644 --- a/tests/snapshots/snapshot__case_7_unsuccessful_run_can_suppress_backtrace.snap +++ b/tests/snapshots/snapshot__case_7_unsuccessful_run_can_suppress_backtrace.snap @@ -1,5 +1,6 @@ --- source: tests/snapshot.rs +assertion_line: 114 expression: run_result.output --- @@ -8,5 +9,6 @@ expression: run_result.output ──────────────────────────────────────────────────────────────────────────────── ERROR panicked at 'explicit panic' ──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO program has used at least 0.16/254.93 KiB (0.1%) of stack space (HOST) ERROR the program panicked diff --git a/tests/snapshots/snapshot__ctrl_c_by_user_is_reported_as_such.snap b/tests/snapshots/snapshot__ctrl_c_by_user_is_reported_as_such.snap index 60a6f287..b4b092cc 100644 --- a/tests/snapshots/snapshot__ctrl_c_by_user_is_reported_as_such.snap +++ b/tests/snapshots/snapshot__ctrl_c_by_user_is_reported_as_such.snap @@ -1,6 +1,6 @@ --- source: tests/snapshot.rs -assertion_line: 123 +assertion_line: 124 expression: run_result.output --- @@ -8,6 +8,7 @@ expression: run_result.output (HOST) INFO success! ──────────────────────────────────────────────────────────────────────────────── ──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO program has used at least 0.13/254.93 KiB (0.1%) of stack space stack backtrace: 0: silent_loop::__cortex_m_rt_main at /tmp/app/src/bin/silent-loop.rs:9:5