Skip to content

Commit 4329dde

Browse files
daniel-nolandmvachhar
authored andcommitted
fix(stats): numeric overflow
There were various chances for numeric overflow found by the fuzzer. These are not especially realistic outcomes if the packet counter is working correctly, but it costs very little to fix them. Signed-off-by: Daniel Noland <[email protected]>
1 parent cabad59 commit 4329dde

File tree

1 file changed

+16
-14
lines changed

1 file changed

+16
-14
lines changed

stats/src/rate.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,9 @@ impl Derivative for SavitzkyGolayFilter<u64> {
130130
itr.next().unwrap_or_else(|| unreachable!()),
131131
itr.next().unwrap_or_else(|| unreachable!()),
132132
];
133-
let weighted_sum =
134-
(8 * (data[3].saturating_sub(data[1]))).saturating_sub(data[4].saturating_sub(data[0]));
133+
let weighted_sum = 8u64
134+
.saturating_mul(data[3].saturating_sub(data[1]))
135+
.saturating_sub(data[4].saturating_sub(data[0]));
135136
let step: f64 = self.step.as_micros() as f64 / 1_000_000.;
136137
if weighted_sum == 0 {
137138
const NORMALIZATION: f64 = 2.;
@@ -159,8 +160,9 @@ impl Derivative for SavitzkyGolayFilter<PacketAndByte<u64>> {
159160
itr.next().unwrap_or_else(|| unreachable!()),
160161
itr.next().unwrap_or_else(|| unreachable!()),
161162
];
162-
let weighted_sum_bytes =
163-
(8 * (data[3].bytes - data[1].bytes)).saturating_sub(data[4].bytes - data[0].bytes);
163+
let weighted_sum_bytes = 8u64
164+
.saturating_mul(data[3].bytes - data[1].bytes)
165+
.saturating_sub(data[4].bytes - data[0].bytes);
164166
let step: f64 = self.step.as_micros() as f64 / 1_000_000.;
165167
if weighted_sum_bytes == 0 {
166168
const NORMALIZATION: f64 = 2.;
@@ -170,7 +172,8 @@ impl Derivative for SavitzkyGolayFilter<PacketAndByte<u64>> {
170172
bytes: data[3].bytes.saturating_sub(data[1].bytes) as f64 / (NORMALIZATION * step),
171173
});
172174
}
173-
let weighted_sum_packets = (8 * (data[3].packets.saturating_sub(data[1].packets)))
175+
let weighted_sum_packets = 8u64
176+
.saturating_mul(data[3].packets.saturating_sub(data[1].packets))
174177
.saturating_sub(data[4].packets.saturating_sub(data[0].packets));
175178
const NORMALIZATION: f64 = 12.;
176179
let packets = weighted_sum_packets as f64 / (NORMALIZATION * step);
@@ -491,19 +494,16 @@ mod contract {
491494

492495
impl TypeGenerator for SavitzkyGolayFilter<PacketAndByte<u64>> {
493496
fn generate<D: Driver>(driver: &mut D) -> Option<Self> {
494-
// we use % to mitigate overflows in this generator.
495497
let mut step = driver.produce()?;
496498
if step == Duration::ZERO {
497499
step += Duration::from_secs(1);
498500
}
499501
let mut filter = SavitzkyGolayFilter::new(step);
500502
let entries: u8 = driver.produce::<u8>()? % 15;
501503
let mut state = driver.produce::<PacketAndByte<u64>>()?;
502-
state.packets %= u64::MAX / 32;
503-
state.bytes %= u64::MAX / 32;
504504
for _ in 0..entries {
505-
state.packets += driver.produce::<u64>()? % (u64::MAX / 32);
506-
state.bytes += driver.produce::<u64>()? % (u64::MAX / 32);
505+
state.packets = state.packets.saturating_add(driver.produce::<u64>()?);
506+
state.bytes = state.bytes.saturating_add(driver.produce::<u64>()?);
507507
filter.push(state);
508508
}
509509
Some(filter)
@@ -528,8 +528,8 @@ mod contract {
528528
state.dst.insert(k, v);
529529
}
530530
Some(x) => {
531-
x.packets += v.packets;
532-
x.bytes += v.bytes;
531+
x.packets = x.packets.saturating_add(v.packets);
532+
x.bytes = x.bytes.saturating_add(v.bytes);
533533
}
534534
}
535535
}
@@ -723,8 +723,10 @@ mod test {
723723
.for_each(
724724
|x: &SavitzkyGolayFilter<PacketAndByte<u64>>| match x.derivative() {
725725
Ok(x) => {
726-
assert!(x.packets >= 0.0);
727-
assert!(x.bytes >= 0.0);
726+
if !x.packets.is_nan() {
727+
assert!(x.packets >= 0.0);
728+
assert!(x.bytes >= 0.0);
729+
}
728730
}
729731
Err(DerivativeError::NotEnoughSamples(s)) => {
730732
assert_eq!(x.idx, s);

0 commit comments

Comments
 (0)