From 4031d97baca14e7ec379d93124bbf31aacb0ff3f Mon Sep 17 00:00:00 2001 From: trinity-1686a Date: Tue, 23 Jun 2026 00:03:17 +0200 Subject: [PATCH] fix overflow on large jumps in linear sequence new limit prevent an overflow in eval which caused the residual to be 64b when a slop of zero would give a smaller one --- .../u64_based/blockwise_linear.rs | 22 +++++++++++++++++++ columnar/src/column_values/u64_based/line.rs | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/columnar/src/column_values/u64_based/blockwise_linear.rs b/columnar/src/column_values/u64_based/blockwise_linear.rs index e37f9098c2..b60bf5bade 100644 --- a/columnar/src/column_values/u64_based/blockwise_linear.rs +++ b/columnar/src/column_values/u64_based/blockwise_linear.rs @@ -241,6 +241,28 @@ mod tests { use super::*; use crate::column_values::u64_based::tests::create_and_validate; + // A block boundary where a high run ends and a low run begins: y0 ≈ 2^32, y511 ≈ 0. + // This large jump used to cause an overflow which made us render all value on 64b + // when 32 was enough. + fn large_descending_jump_vals() -> Vec { + let high_start: u64 = 4_294_967_039; // ≈ 2^32 - 257 + (0u64..256) + .map(|i| high_start + i) + .chain(0u64..256) + .collect() + } + + #[test] + fn test_blockwise_linear_large_descending_jump_uses_at_most_32bit() { + let vals = large_descending_jump_vals(); + let (_, actual_rate) = + create_and_validate::(&vals, "large descending jump").unwrap(); + assert!( + actual_rate <= 0.6, + "compression rate {actual_rate:.3} is too high (bug: 64-bit residuals)" + ); + } + #[test] fn test_with_codec_data_sets_simple() { create_and_validate::( diff --git a/columnar/src/column_values/u64_based/line.rs b/columnar/src/column_values/u64_based/line.rs index 4e6d4802d5..135780635f 100644 --- a/columnar/src/column_values/u64_based/line.rs +++ b/columnar/src/column_values/u64_based/line.rs @@ -37,7 +37,7 @@ fn compute_slope(y0: u64, y1: u64, num_vals: NonZeroU32) -> u64 { } else { y0.wrapping_sub(y1) }; - if abs_dy >= 1 << 32 { + if abs_dy >= 1 << 31 { // This is outside of realm we handle. // Let's just bail. return 0u64;