Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check histogram bin overflow in the support type, not the power type #6409

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions oximeter/types/src/histogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,8 +1029,13 @@ where
return Err(QuantizationError::InvalidSteps);
}

// The highest power must be representable in the target type.
if self.checked_pow(hi.into()).is_none() {
// The highest power must be representable in the target type. Note that
// we have to convert to that target type _before_ doing this check.
let base = <u64 as From<Self>>::from(*self);
bnaecker marked this conversation as resolved.
Show resolved Hide resolved
let Some(highest) = base.checked_pow(hi.into()) else {
return Err(QuantizationError::Overflow);
};
if <T as NumCast>::from(highest).is_none() {
return Err(QuantizationError::Overflow);
}

Expand All @@ -1039,7 +1044,6 @@ where
//
// Note that we unwrap in a few places below, where we're sure the
// narrowing conversion cannot fail, such as to a u32.
let base = <u64 as From<Self>>::from(*self);
let lo = <u64 as From<Self>>::from(lo);
let hi = <u64 as From<Self>>::from(hi);
let count = <u64 as NumCast>::from(count.get())
Expand All @@ -1057,7 +1061,6 @@ where
let lo = base.pow(lo as _);
let hi = base.pow(hi as _);
let distance = hi - lo;
dbg!(distance, count);
distance.is_multiple_of(&count)
})
}
Expand Down Expand Up @@ -1767,4 +1770,31 @@ mod tests {
HistogramError::EmptyBins
));
}

#[test]
fn test_log_linear_bins_does_not_overflow_wide_bin_type() {
let start: u16 = 3;
// 10u16 ** 10u16 overflows, but what we should be computing is 10u64 **
// 10u16, which would not overflow. We need to compute whether it
// overflows in the _support_ type.
let stop = 10;
Histogram::<u64>::span_decades(start, stop).expect(
"expected not to overflow, since support type is wide enough",
);
}

#[test]
fn test_log_linear_bins_does_overflow_narrow_bin_type() {
// In this case, the start / stop powers _and_ their resulting bins are
// both representable as u16s and also u64s. But we're generating bins
// that are u8s, which _the powers do_ overflow.
let start: u16 = 1;
let stop: u16 = 4;
Histogram::<u32>::span_decades(start, stop).expect(
"expected not to overflow a u32, since support type is wide enough",
);
Histogram::<u8>::span_decades(start, stop).expect_err(
"expected to overflow a u8, since support type is not wide enough",
);
}
}
Loading