From a424e76e53e086147936f7e582b9e01423a206b8 Mon Sep 17 00:00:00 2001 From: Julian Frimmel Date: Sun, 22 Sep 2024 20:59:03 +0200 Subject: [PATCH 1/4] Move `display_*`-functions to own module --- src/main.rs | 70 ++------------------------------------------------- src/output.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 68 deletions(-) create mode 100644 src/output.rs diff --git a/src/main.rs b/src/main.rs index cb6b7ba..46007b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ )] mod driver; +mod output; mod panic; mod valgrind; @@ -25,73 +26,6 @@ use colored::Colorize as _; use std::env; use std::process; -/// Nicely format the errors in the valgrind output, if there are any. -fn display_errors(errors: &[valgrind::xml::Error]) { - // format the output in a helpful manner - for error in errors { - if error.kind.is_leak() { - display_leak(error); - } else { - display_generic_error(error); - } - } - - let total: usize = errors.iter().map(|error| error.resources.bytes).sum(); - eprintln!( - "{:>12} Leaked {} total ({} other errors)", - "Summary".red().bold(), - bytesize::to_string(total as _, true), - errors.iter().filter(|e| !e.kind.is_leak()).count() - ); -} - -/// Nicely format a single memory leak error. -fn display_leak(error: &valgrind::xml::Error) { - eprintln!( - "{:>12} leaked {} in {} block{}", - "Error".red().bold(), - bytesize::to_string(error.resources.bytes as _, true), - error.resources.blocks, - if error.resources.blocks == 1 { "" } else { "s" } - ); - - let stack = &error.stack_trace[0]; // always available - display_stack_trace("stack trace (user code at the bottom)", stack); -} - -/// Nicely format a non-memory-leak error. -fn display_generic_error(error: &valgrind::xml::Error) { - eprintln!( - "{:>12} {}", - "Error".red().bold(), - error.main_info.as_ref().map_or("unknown", String::as_str) - ); - - let stack = &error.stack_trace[0]; // always available - display_stack_trace("main stack trace (user code at the bottom)", stack); - error - .stack_trace - .iter() - .skip(1) - .enumerate() - .map(|(index, stack)| (error.auxiliary_info.get(index), stack)) - .for_each(|(msg, stack)| { - display_stack_trace( - msg.map_or_else(|| "additional stack trace", String::as_str), - stack, - ); - }); -} - -/// Write out the full stack trace (indented to match other messages). -fn display_stack_trace(msg: &str, stack: &valgrind::xml::Stack) { - eprintln!("{:>12} {}", "Info".cyan().bold(), msg); - stack - .frames - .iter() - .for_each(|frame| eprintln!(" at {frame}")); -} - fn main() { panic::replace_hook(); @@ -134,7 +68,7 @@ fn main() { errors: Some(errors), .. }) => { - display_errors(&errors); + output::display_errors(&errors); 127 } Ok(_) => 0, diff --git a/src/output.rs b/src/output.rs new file mode 100644 index 0000000..2e3b095 --- /dev/null +++ b/src/output.rs @@ -0,0 +1,70 @@ +//! Write human-readable and colored output the the console. +use crate::valgrind; +use colored::Colorize as _; + +/// Nicely format the errors in the valgrind output, if there are any. +pub fn display_errors(errors: &[valgrind::xml::Error]) { + // format the output in a helpful manner + for error in errors { + if error.kind.is_leak() { + display_leak(error); + } else { + display_generic_error(error); + } + } + + let total: usize = errors.iter().map(|error| error.resources.bytes).sum(); + eprintln!( + "{:>12} Leaked {} total ({} other errors)", + "Summary".red().bold(), + bytesize::to_string(total as _, true), + errors.iter().filter(|e| !e.kind.is_leak()).count() + ); +} + +/// Nicely format a single memory leak error. +fn display_leak(error: &valgrind::xml::Error) { + eprintln!( + "{:>12} leaked {} in {} block{}", + "Error".red().bold(), + bytesize::to_string(error.resources.bytes as _, true), + error.resources.blocks, + if error.resources.blocks == 1 { "" } else { "s" } + ); + + let stack = &error.stack_trace[0]; // always available + display_stack_trace("stack trace (user code at the bottom)", stack); +} + +/// Nicely format a non-memory-leak error. +fn display_generic_error(error: &valgrind::xml::Error) { + eprintln!( + "{:>12} {}", + "Error".red().bold(), + error.main_info.as_ref().map_or("unknown", String::as_str) + ); + + let stack = &error.stack_trace[0]; // always available + display_stack_trace("main stack trace (user code at the bottom)", stack); + error + .stack_trace + .iter() + .skip(1) + .enumerate() + .map(|(index, stack)| (error.auxiliary_info.get(index), stack)) + .for_each(|(msg, stack)| { + display_stack_trace( + msg.map_or_else(|| "additional stack trace", String::as_str), + stack, + ); + }); +} + +/// Write out the full stack trace (indented to match other messages). +fn display_stack_trace(msg: &str, stack: &valgrind::xml::Stack) { + eprintln!("{:>12} {}", "Info".cyan().bold(), msg); + stack + .frames + .iter() + .for_each(|frame| eprintln!(" at {frame}")); +} From a4fe60174710c26e1d535481b7454625ed472152 Mon Sep 17 00:00:00 2001 From: Julian Frimmel Date: Sun, 22 Sep 2024 21:02:15 +0200 Subject: [PATCH 2/4] Extract stack-overflow output printing to module --- src/main.rs | 8 +------- src/output.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 46007b1..2cc5628 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,13 +78,7 @@ fn main() { Err(valgrind::Error::ValgrindFailure(output)) if output.contains("main thread stack using the --main-stacksize= flag") => { - let error = "Error".red().bold(); - let info = "Info".cyan().bold(); - eprintln!("{error:>12}: looks like the program overflowed its stack"); - eprintln!("{info:>12}: valgrind says:"); - output - .lines() - .for_each(|line| eprintln!(" {line}")); + output::display_stack_overflow(&output); 134 // default exit code for stack overflows } Err(e) => { diff --git a/src/output.rs b/src/output.rs index 2e3b095..f7288e6 100644 --- a/src/output.rs +++ b/src/output.rs @@ -68,3 +68,14 @@ fn display_stack_trace(msg: &str, stack: &valgrind::xml::Stack) { .iter() .for_each(|frame| eprintln!(" at {frame}")); } + +/// Write out an error message for describing the stack overflow message. +pub fn display_stack_overflow(output: &str) { + let error = "Error".red().bold(); + let info = "Info".cyan().bold(); + eprintln!("{error:>12}: looks like the program overflowed its stack"); + eprintln!("{info:>12}: valgrind says:"); + output + .lines() + .for_each(|line| eprintln!(" {line}")); +} From 28a37a5ac0403d60540f3b3e214b44cbcb8d3aa3 Mon Sep 17 00:00:00 2001 From: Julian Frimmel Date: Sun, 22 Sep 2024 21:03:20 +0200 Subject: [PATCH 3/4] Move stack overflow message to constant --- src/main.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2cc5628..160973b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,10 @@ use colored::Colorize as _; use std::env; use std::process; +/// Part of the output message of `valgrind` if a possible stack overflow is +/// detected. +const STACK_OVERFLOW: &str = "main thread stack using the --main-stacksize= flag"; + fn main() { panic::replace_hook(); @@ -75,9 +79,7 @@ fn main() { Err(e @ valgrind::Error::MalformedOutput(..)) => { panic_with!(e); } - Err(valgrind::Error::ValgrindFailure(output)) - if output.contains("main thread stack using the --main-stacksize= flag") => - { + Err(valgrind::Error::ValgrindFailure(output)) if output.contains(STACK_OVERFLOW) => { output::display_stack_overflow(&output); 134 // default exit code for stack overflows } From 66cd2b72ebced0c8885cd7e7e163e1af1c02a847 Mon Sep 17 00:00:00 2001 From: Julian Frimmel Date: Sun, 22 Sep 2024 21:04:45 +0200 Subject: [PATCH 4/4] Remove `panic_with!`-macro only used once --- src/main.rs | 4 +--- src/panic.rs | 11 ----------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index 160973b..b98a303 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,9 +76,7 @@ fn main() { 127 } Ok(_) => 0, - Err(e @ valgrind::Error::MalformedOutput(..)) => { - panic_with!(e); - } + Err(e @ valgrind::Error::MalformedOutput(..)) => std::panic::panic_any(e), // the panic handler catches this and reports it appropriately Err(valgrind::Error::ValgrindFailure(output)) if output.contains(STACK_OVERFLOW) => { output::display_stack_overflow(&output); 134 // default exit code for stack overflows diff --git a/src/panic.rs b/src/panic.rs index 4a91313..f652c40 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -29,17 +29,6 @@ const PANIC_HEADER: &str = " how to reproduce it. "; -/// Panic with a custom panic output. -/// -/// This is helpful for printing debug information to the panic message. -#[macro_export] -#[allow(clippy::module_name_repetitions)] // necessary for exported macro -macro_rules! panic_with { - ($e:expr) => { - std::panic::panic_any($e) - }; -} - /// Replaces any previous hook with the custom hook of this application. /// /// This custom hook points the user to the project repository and asks them to