From 8138083ef8e54ccfb880927fbf275c8b84695d77 Mon Sep 17 00:00:00 2001 From: Joshua Magady Date: Sun, 15 Feb 2026 12:33:04 -0600 Subject: [PATCH] fix(spec): use saturating_sub in snapshot summary to prevent overflow panic --- crates/iceberg/src/spec/snapshot_summary.rs | 33 ++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/crates/iceberg/src/spec/snapshot_summary.rs b/crates/iceberg/src/spec/snapshot_summary.rs index c67ee37d3e..bc1d81800a 100644 --- a/crates/iceberg/src/spec/snapshot_summary.rs +++ b/crates/iceberg/src/spec/snapshot_summary.rs @@ -509,7 +509,7 @@ fn update_totals( .get(removed_property) .map(|value| value.parse::().unwrap()) { - new_total -= value; + new_total = new_total.saturating_sub(value); } summary .additional_properties @@ -1017,4 +1017,35 @@ mod tests { .all(|(k, _)| !k.starts_with(CHANGED_PARTITION_PREFIX)) ); } + + #[test] + fn test_update_totals_saturating_sub_no_panic() { + // removed > previous_total + added → should saturate to 0, not panic + let mut summary = Summary { + operation: Operation::Overwrite, + additional_properties: HashMap::from([ + (DELETED_DATA_FILES.to_string(), "15".to_string()), + (ADDED_DATA_FILES.to_string(), "1".to_string()), + ]), + }; + let previous = Summary { + operation: Operation::Append, + additional_properties: HashMap::from([( + TOTAL_DATA_FILES.to_string(), + "10".to_string(), + )]), + }; + // 10 + 1 - 15 = underflow on u64 → should be 0 + update_totals( + &mut summary, + Some(&previous), + TOTAL_DATA_FILES, + ADDED_DATA_FILES, + DELETED_DATA_FILES, + ); + assert_eq!( + summary.additional_properties.get(TOTAL_DATA_FILES).unwrap(), + "0" + ); + } }