From f4c0f6a4516c5a2b764e2e653a7d55150e8f6e30 Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Wed, 2 Sep 2026 13:47:12 +0300 Subject: [PATCH] fix(file source): fix duration subtraction overflow in TimingStats::report Signed-off-by: Vitalii Parfonov --- lib/file-source/src/file_server.rs | 45 +++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/file-source/src/file_server.rs b/lib/file-source/src/file_server.rs index ebb1867339242..e8ec143fd7d5d 100644 --- a/lib/file-source/src/file_server.rs +++ b/lib/file-source/src/file_server.rs @@ -518,9 +518,12 @@ impl TimingStats { } fn report(&self) { + if !tracing::level_enabled!(tracing::Level::DEBUG) { + return; + } let total = self.started_at.elapsed(); let counted: Duration = self.segments.values().sum(); - let other: Duration = self.started_at.elapsed() - counted; + let other: Duration = total.saturating_sub(counted); let mut ratios = self .segments .iter() @@ -569,3 +572,43 @@ pub struct Line { pub start_offset: u64, pub end_offset: u64, } + +#[cfg(test)] +mod tests { + use super::*; + use std::time::Duration; + + #[test] + fn timing_stats_handles_duration_subtraction_overflow() { + let mut stats = TimingStats::default(); + + // Record segments with durations + stats.record("io", Duration::from_millis(50)); + stats.record("processing", Duration::from_millis(45)); + stats.record_bytes(1024); + + // The key test: calling report() should NOT panic even if + // recorded segments briefly exceed elapsed time due to timing + // precision issues or clock adjustments (which happens on + // busy systems or with system clock adjustments). + // Before the fix, this could panic with "overflow when subtracting durations". + stats.report(); + } + + #[test] + fn timing_stats_saturating_sub_clamps_to_zero() { + // Directly test the saturating_sub behavior + let total = Duration::from_millis(100); + let counted_normal = Duration::from_millis(90); + let counted_overflow = Duration::from_millis(105); + + // Normal case: subtraction succeeds + assert_eq!( + total.saturating_sub(counted_normal), + Duration::from_millis(10) + ); + + // Overflow case: saturating_sub clamps to zero instead of panicking + assert_eq!(total.saturating_sub(counted_overflow), Duration::ZERO); + } +}