From d351a823ab9581e2783a53707eeaf8da2192e607 Mon Sep 17 00:00:00 2001 From: Em Sharnoff Date: Tue, 24 Jun 2025 22:38:34 +0100 Subject: [PATCH 1/3] summarize: Don't panic on broken pipe I hit #31 while piping summarize to head. The original issue was in part due to `prettytable` panicking. That's since been upgraded to a version with the fix, but some of the `println!`s that happen after `table.printstd()` will also panic from the broken pipe: $ summarize summarize ... | head ... thread 'main' panicked at library/std/src/io/stdio.rs:1165:9: failed printing to stdout: Broken pipe (os error 32) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace To fix this, change the `println!`s to `writeln!`s, and ignore any errors. Fixes #31. --- summarize/src/main.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/summarize/src/main.rs b/summarize/src/main.rs index 9c3ce65..8a41c45 100644 --- a/summarize/src/main.rs +++ b/summarize/src/main.rs @@ -5,7 +5,7 @@ use analyzeme::AnalysisResults; use analyzeme::ProfilingData; use std::error::Error; use std::fs::File; -use std::io::{BufReader, BufWriter}; +use std::io::{BufReader, BufWriter, Write}; use std::{path::PathBuf, time::Duration}; use clap::Parser; @@ -142,7 +142,11 @@ fn diff(opt: DiffOpt) -> Result<(), Box> { table.printstd(); - println!("Total cpu time: {:?}", results.total_time); + _ = writeln!( + std::io::stdout(), + "Total cpu time: {:?}", + results.total_time + ); let mut table = Table::new(); @@ -286,10 +290,15 @@ fn summarize(opt: SummarizeOpt) -> Result<(), Box> { table.printstd(); - println!("Total cpu time: {:?}", results.total_time); + _ = writeln!( + std::io::stdout(), + "Total cpu time: {:?}", + results.total_time + ); if percent_above != 0.0 { - println!( + _ = writeln!( + std::io::stdout(), "Filtered results account for {:.3}% of total time.", percent_total_time ); From 59876d95f6dac8adaf18331269baf323a83e5b6f Mon Sep 17 00:00:00 2001 From: Em Sharnoff Date: Tue, 24 Jun 2025 22:58:11 +0100 Subject: [PATCH 2/3] exit(1) if writeln! to stdout fails --- summarize/src/main.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/summarize/src/main.rs b/summarize/src/main.rs index 8a41c45..d72077b 100644 --- a/summarize/src/main.rs +++ b/summarize/src/main.rs @@ -142,11 +142,15 @@ fn diff(opt: DiffOpt) -> Result<(), Box> { table.printstd(); - _ = writeln!( + let res = writeln!( std::io::stdout(), "Total cpu time: {:?}", results.total_time ); + if res.is_err() { + // there's something wrong with stdout - give up on writing more + std::process::exit(1); + } let mut table = Table::new(); @@ -290,18 +294,26 @@ fn summarize(opt: SummarizeOpt) -> Result<(), Box> { table.printstd(); - _ = writeln!( + let res = writeln!( std::io::stdout(), "Total cpu time: {:?}", results.total_time ); + if res.is_err() { + // there's something wrong with stdout - give up on writing more + std::process::exit(1); + } if percent_above != 0.0 { - _ = writeln!( + let res = writeln!( std::io::stdout(), "Filtered results account for {:.3}% of total time.", percent_total_time ); + if res.is_err() { + // there's something wrong with stdout - give up on writing more + std::process::exit(1); + } } let mut table = Table::new(); From 75fde69f873e090a71dc3eacecb2273cd7585ac9 Mon Sep 17 00:00:00 2001 From: Em Sharnoff Date: Fri, 27 Jun 2025 18:50:15 +0100 Subject: [PATCH 3/3] exit on BrokenPipe, return err otherwise --- summarize/src/main.rs | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/summarize/src/main.rs b/summarize/src/main.rs index d72077b..8cdf521 100644 --- a/summarize/src/main.rs +++ b/summarize/src/main.rs @@ -94,6 +94,17 @@ fn aggregate(opt: AggregateOpt) -> Result<(), Box> { Ok(()) } +fn write_stdout(fmt_args: std::fmt::Arguments) -> Result<(), Box> { + std::io::stdout().write_fmt(fmt_args).map_err(|e| { + if matches!(e.kind(), std::io::ErrorKind::BrokenPipe) { + // Broken pipes are somewhat expected, exit without writing anything else. + std::process::exit(0); + } + + format!("failed writing to stdout: {e}").into() + }) +} + fn diff(opt: DiffOpt) -> Result<(), Box> { let base = process_results(&opt.base)?; let change = process_results(&opt.change)?; @@ -142,15 +153,7 @@ fn diff(opt: DiffOpt) -> Result<(), Box> { table.printstd(); - let res = writeln!( - std::io::stdout(), - "Total cpu time: {:?}", - results.total_time - ); - if res.is_err() { - // there's something wrong with stdout - give up on writing more - std::process::exit(1); - } + write_stdout(format_args!("Total cpu time: {:?}\n", results.total_time))?; let mut table = Table::new(); @@ -294,26 +297,13 @@ fn summarize(opt: SummarizeOpt) -> Result<(), Box> { table.printstd(); - let res = writeln!( - std::io::stdout(), - "Total cpu time: {:?}", - results.total_time - ); - if res.is_err() { - // there's something wrong with stdout - give up on writing more - std::process::exit(1); - } + write_stdout(format_args!("Total cpu time: {:?}\n", results.total_time))?; if percent_above != 0.0 { - let res = writeln!( - std::io::stdout(), - "Filtered results account for {:.3}% of total time.", + write_stdout(format_args!( + "Filtered results account for {:.3}% of total time.\n", percent_total_time - ); - if res.is_err() { - // there's something wrong with stdout - give up on writing more - std::process::exit(1); - } + ))?; } let mut table = Table::new();