From c67fc2e4c5cf062725458108042dd89d618bd8de Mon Sep 17 00:00:00 2001 From: miguel raz Date: Mon, 25 Jan 2021 17:58:29 -0600 Subject: [PATCH] Add guards/tests for div,rem overflow cases --- crates/core_simd/src/ops.rs | 29 +++++++++- crates/core_simd/tests/ops_impl/int_macros.rs | 57 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs index a21e9ab5bf1..51e97757c54 100644 --- a/crates/core_simd/src/ops.rs +++ b/crates/core_simd/src/ops.rs @@ -283,13 +283,20 @@ macro_rules! impl_unsigned_int_ops { #[inline] fn div(self, rhs: Self) -> Self::Output { - // TODO there is probably a better way of doing this - if AsRef::<[$scalar]>::as_ref(&rhs) + if rhs.as_slice() .iter() .any(|x| *x == 0) { panic!("attempt to divide by zero"); } + + // Guards for div(MIN, -1), + // this check only applies to signed ints + if <$scalar>::MIN != 0 && self.as_slice().iter() + .zip(rhs.as_slice().iter()) + .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { + panic!("attempt to divide with overflow"); + } unsafe { crate::intrinsics::simd_div(self, rhs) } } } @@ -304,6 +311,11 @@ macro_rules! impl_unsigned_int_ops { if rhs == 0 { panic!("attempt to divide by zero"); } + if <$scalar>::MIN != 0 && + self.as_slice().iter().any(|x| *x == <$scalar>::MIN) && + rhs == -1 as _ { + panic!("attempt to divide with overflow"); + } let rhs = Self::splat(rhs); unsafe { crate::intrinsics::simd_div(self, rhs) } } @@ -353,6 +365,14 @@ macro_rules! impl_unsigned_int_ops { { panic!("attempt to calculate the remainder with a divisor of zero"); } + + // Guards for rem(MIN, -1) + // this branch applies the check only to signed ints + if <$scalar>::MIN != 0 && self.as_slice().iter() + .zip(rhs.as_slice().iter()) + .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { + panic!("attempt to calculate the remainder with overflow"); + } unsafe { crate::intrinsics::simd_rem(self, rhs) } } } @@ -367,6 +387,11 @@ macro_rules! impl_unsigned_int_ops { if rhs == 0 { panic!("attempt to calculate the remainder with a divisor of zero"); } + if <$scalar>::MIN != 0 && + self.as_slice().iter().any(|x| *x == <$scalar>::MIN) && + rhs == -1 as _ { + panic!("attempt to calculate the remainder with overflow"); + } let rhs = Self::splat(rhs); unsafe { crate::intrinsics::simd_rem(self, rhs) } } diff --git a/crates/core_simd/tests/ops_impl/int_macros.rs b/crates/core_simd/tests/ops_impl/int_macros.rs index af956aa3e52..43c75c6a9c4 100644 --- a/crates/core_simd/tests/ops_impl/int_macros.rs +++ b/crates/core_simd/tests/ops_impl/int_macros.rs @@ -228,6 +228,39 @@ macro_rules! int_tests { assert_biteq!(a, expected); } + #[test] + #[should_panic] + fn div_min_panics() { + let a = from_slice(&vec![$scalar::MIN; 64]); + let b = from_slice(&vec![-1; 64]); + let _ = a / b; + } + + #[test] + #[should_panic] + fn div_by_all_zeros_panics() { + let a = from_slice(&A); + let b = from_slice(&vec![0 ; 64]); + let _ = a / b; + } + + #[test] + #[should_panic] + fn div_by_one_zero_panics() { + let a = from_slice(&A); + let mut b = from_slice(&B); + b[0] = 0 as _; + let _ = a / b; + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn div_min_neg_one_no_panic() { + let a = from_slice(&A); + let b = from_slice(&vec![-1; 64]); + let _ = a / b; + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn rem() { @@ -275,6 +308,30 @@ macro_rules! int_tests { assert_biteq!(a, expected); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn rem_min_neg_one_no_panic() { + let a = from_slice(&A); + let b = from_slice(&vec![-1; 64]); + let _ = a % b; + } + + #[test] + #[should_panic] + fn rem_min_panic() { + let a = from_slice(&vec![$scalar::MIN; 64]); + let b = from_slice(&vec![-1 ; 64]); + let _ = a % b; + } + + #[test] + #[should_panic] + fn rem_min_zero_panic() { + let a = from_slice(&A); + let b = from_slice(&vec![0 ; 64]); + let _ = a % b; + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn bitand() {