From 9d277694b069bb21d4c92e987f96ef3fb1314b1a Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 26 Feb 2022 08:19:21 -0300 Subject: [PATCH 01/14] Fix Clippy diagnostics --- src/lib.rs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b59b2fc..b3017fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ macro_rules! array_refs { use std::slice; #[inline] #[allow(unused_assignments)] - #[allow(eval_order_dependence)] + #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &[T]) -> ( $( &[T; $pre], )* &[T], $( &[T; $post], )*) { let min_len = $( $pre + )* $( $post + )* 0; let var_len = a.len() - min_len; @@ -116,15 +116,15 @@ macro_rules! array_refs { let mut p = a.as_ptr(); ( $( { let aref = & *(p as *const [T; $pre]); - p = p.offset($pre as isize); + p = p.add($pre); aref } ),* , { let sl = slice::from_raw_parts(p as *const T, var_len); - p = p.offset(var_len as isize); + p = p.add(var_len); sl }, $( { let aref = & *(p as *const [T; $post]); - p = p.offset($post as isize); + p = p.add($post); aref } ),*) } @@ -139,7 +139,7 @@ macro_rules! array_refs { { #[inline] #[allow(unused_assignments)] - #[allow(eval_order_dependence)] + #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &[T; $( $len + )* 0 ]) -> ( $( &[T; $len], )* ) { let mut p = a.as_ptr(); ( $( { @@ -205,7 +205,7 @@ macro_rules! mut_array_refs { use std::slice; #[inline] #[allow(unused_assignments)] - #[allow(eval_order_dependence)] + #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &mut [T]) -> ( $( &mut [T; $pre], )* &mut [T], $( &mut [T; $post], )*) { let min_len = $( $pre + )* $( $post + )* 0; let var_len = a.len() - min_len; @@ -213,15 +213,15 @@ macro_rules! mut_array_refs { let mut p = a.as_mut_ptr(); ( $( { let aref = &mut *(p as *mut [T; $pre]); - p = p.offset($pre as isize); + p = p.add($pre); aref } ),* , { let sl = slice::from_raw_parts_mut(p as *mut T, var_len); - p = p.offset(var_len as isize); + p = p.add(var_len); sl }, $( { let aref = &mut *(p as *mut [T; $post]); - p = p.offset($post as isize); + p = p.add($post); aref } ),*) } @@ -236,12 +236,12 @@ macro_rules! mut_array_refs { { #[inline] #[allow(unused_assignments)] - #[allow(eval_order_dependence)] + #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &mut [T; $( $len + )* 0 ]) -> ( $( &mut [T; $len], )* ) { let mut p = a.as_mut_ptr(); ( $( { let aref = &mut *(p as *mut [T; $len]); - p = p.offset($len as isize); + p = p.add($len); aref } ),* ) } @@ -297,6 +297,7 @@ macro_rules! array_mut_ref { } +#[allow(clippy::all)] #[cfg(test)] mod test { @@ -473,4 +474,13 @@ fn test_5_mut_xarray_refs_with_dotdot() { assert_eq!(&[10;10], array_ref![data, 118, 10]); } +#[forbid(clippy::ptr_offset_with_cast)] +#[test] +fn forbidden_clippy_lints_do_not_fire() { + let mut data = [0u8; 32]; + let _ = array_refs![&data, 8; .. ;]; + let _ = mut_array_refs![&mut data, 8; .. ; 10]; +} + } // mod test + From ae7ae54d5137bfc2c3227cefd51a3b9795e58de9 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 9 Sep 2022 08:53:15 -0300 Subject: [PATCH 02/14] Effectively make this project `no_std` Replaces `std::slice` with `core::slice`. The current test suite didn't trigger an error because `std` is imported if `#[cfg(test)]`. --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b3017fa..4c4b418 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ macro_rules! array_ref { macro_rules! array_refs { ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{ { - use std::slice; + use core::slice; #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] @@ -202,7 +202,7 @@ macro_rules! array_refs { macro_rules! mut_array_refs { ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{ { - use std::slice; + use core::slice; #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] From feab803f09f9a2f44df71b16320abdedead62d7e Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Thu, 16 Mar 2023 19:52:42 +0000 Subject: [PATCH 03/14] Fixed single-argument `{mut_}array_refs` returning wrong type. --- src/lib.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4c4b418..3b01639 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,7 +118,7 @@ macro_rules! array_refs { let aref = & *(p as *const [T; $pre]); p = p.add($pre); aref - } ),* , { + }, )* { let sl = slice::from_raw_parts(p as *const T, var_len); p = p.add(var_len); sl @@ -126,7 +126,7 @@ macro_rules! array_refs { let aref = & *(p as *const [T; $post]); p = p.add($post); aref - } ),*) + }, )*) } let input = $arr; #[allow(unused_unsafe)] @@ -146,7 +146,7 @@ macro_rules! array_refs { let aref = &*(p as *const [T; $len]); p = p.offset($len as isize); aref - } ),* ) + }, )* ) } let input = $arr; #[allow(unused_unsafe)] @@ -215,7 +215,7 @@ macro_rules! mut_array_refs { let aref = &mut *(p as *mut [T; $pre]); p = p.add($pre); aref - } ),* , { + }, )* { let sl = slice::from_raw_parts_mut(p as *mut T, var_len); p = p.add(var_len); sl @@ -223,7 +223,7 @@ macro_rules! mut_array_refs { let aref = &mut *(p as *mut [T; $post]); p = p.add($post); aref - } ),*) + }, )*) } let input = $arr; #[allow(unused_unsafe)] @@ -243,7 +243,7 @@ macro_rules! mut_array_refs { let aref = &mut *(p as *mut [T; $len]); p = p.add($len); aref - } ),* ) + }, )* ) } let input = $arr; #[allow(unused_unsafe)] @@ -482,5 +482,21 @@ fn forbidden_clippy_lints_do_not_fire() { let _ = mut_array_refs![&mut data, 8; .. ; 10]; } +#[test] +fn single_arg_refs() { + let mut data = [0u8; 8]; + let (_, ) = array_refs![&data, 8]; + let (_, ) = mut_array_refs![&mut data, 8]; + + let (_, _) = array_refs![&data, 4; ..;]; + let (_, _) = mut_array_refs![&mut data, 4; ..;]; + + let (_, _) = array_refs![&data,; ..; 4]; + let (_, _) = mut_array_refs![&mut data,; ..; 4]; + + let (_,) = array_refs![&data,; ..;]; + let (_,) = mut_array_refs![&mut data,; ..;]; +} + } // mod test From 6a0d5849e359a9ad29ad096997eba3f1c7ca6b64 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Mon, 20 Mar 2023 11:40:49 -0700 Subject: [PATCH 04/14] bump version for various fixes --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6d92097..78dca77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arrayref" -version = "0.3.6" +version = "0.3.7" authors = ["David Roundy "] description = "Macros to take array references of slices" license = "BSD-2-Clause" From 7bb282b6dcce143d32d3f7bb5ac2345c97a08a55 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Fri, 19 Jul 2024 21:00:56 -0700 Subject: [PATCH 05/14] check for overflow (at compile time) in *_refs! (closes #26) --- src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3b01639..581c181 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,14 +105,31 @@ macro_rules! array_ref { macro_rules! array_refs { ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{ { + /// A hokey struct to avoid theoretical overflow, which is only used + /// at compile time, so efficiency of the overflow checks are not of + /// concern. + struct SaturatingUsize(usize); + impl SaturatingUsize { + // It is only used at compile time, so gets incorrectly + // triggered as "dead code". + #[allow(dead_code)] + const fn add(self, rhs: usize) -> Self { + if let Some(v) = self.0.checked_add(rhs) { + SaturatingUsize(v) + } else { + SaturatingUsize(usize::MAX) + } + } + } + use core::slice; #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &[T]) -> ( $( &[T; $pre], )* &[T], $( &[T; $post], )*) { - let min_len = $( $pre + )* $( $post + )* 0; - let var_len = a.len() - min_len; - assert!(a.len() >= min_len); + const MIN_LEN: usize = SaturatingUsize(0) $( .add($pre) )* $( .add($post) )* .0; + let var_len = a.len() - MIN_LEN; + assert!(a.len() >= MIN_LEN); let mut p = a.as_ptr(); ( $( { let aref = & *(p as *const [T; $pre]); @@ -202,14 +219,31 @@ macro_rules! array_refs { macro_rules! mut_array_refs { ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{ { + /// A hokey struct to avoid theoretical overflow, which is only used + /// at compile time, so efficiency of the overflow checks are not of + /// concern. + struct SaturatingUsize(usize); + impl SaturatingUsize { + // It is only used at compile time, so gets incorrectly + // triggered as "dead code". + #[allow(dead_code)] + const fn add(self, rhs: usize) -> Self { + if let Some(v) = self.0.checked_add(rhs) { + SaturatingUsize(v) + } else { + SaturatingUsize(usize::MAX) + } + } + } + use core::slice; #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &mut [T]) -> ( $( &mut [T; $pre], )* &mut [T], $( &mut [T; $post], )*) { - let min_len = $( $pre + )* $( $post + )* 0; - let var_len = a.len() - min_len; - assert!(a.len() >= min_len); + const MIN_LEN: usize = SaturatingUsize(0) $( .add($pre) )* $( .add($post) )* .0; + let var_len = a.len() - MIN_LEN; + assert!(a.len() >= MIN_LEN); let mut p = a.as_mut_ptr(); ( $( { let aref = &mut *(p as *mut [T; $pre]); From 0d6e80ba8df08c41cc26b1a9ae1b27157a691dbd Mon Sep 17 00:00:00 2001 From: David Roundy Date: Fri, 19 Jul 2024 21:01:09 -0700 Subject: [PATCH 06/14] cargo fmt --- examples/array_refs.rs | 10 +- examples/array_refs_with_const.rs | 10 +- examples/simple-case.rs | 2 +- src/lib.rs | 322 +++++++++++++++--------------- 4 files changed, 168 insertions(+), 176 deletions(-) diff --git a/examples/array_refs.rs b/examples/array_refs.rs index a3ff081..c7e0dd1 100644 --- a/examples/array_refs.rs +++ b/examples/array_refs.rs @@ -2,12 +2,12 @@ extern crate arrayref; fn main() { - let x = [0,1,2,3,4,5,6,7,8,9]; - let (a,b,c) = array_refs!(&x, 2, 3, 5); + let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let (a, b, c) = array_refs!(&x, 2, 3, 5); assert_eq!(2, a.len()); assert_eq!(3, b.len()); assert_eq!(5, c.len()); - assert_eq!(*a, [0,1]); - assert_eq!(*b, [2,3,4]); - assert_eq!(*c, [5,6,7,8,9]); + assert_eq!(*a, [0, 1]); + assert_eq!(*b, [2, 3, 4]); + assert_eq!(*c, [5, 6, 7, 8, 9]); } diff --git a/examples/array_refs_with_const.rs b/examples/array_refs_with_const.rs index 734ef46..8f66d4e 100644 --- a/examples/array_refs_with_const.rs +++ b/examples/array_refs_with_const.rs @@ -7,12 +7,12 @@ const SIZE_B: usize = 3; const SIZE_C: usize = 5; fn main() { - let x: [u8; SIZE] = [0,1,2,3,4,5,6,7,8,9]; - let (a,b,c) = array_refs!(&x, SIZE_A, SIZE_B, SIZE_C); + let x: [u8; SIZE] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let (a, b, c) = array_refs!(&x, SIZE_A, SIZE_B, SIZE_C); assert_eq!(SIZE_A, a.len()); assert_eq!(SIZE_B, b.len()); assert_eq!(SIZE_C, c.len()); - assert_eq!(*a, [0,1]); - assert_eq!(*b, [2,3,4]); - assert_eq!(*c, [5,6,7,8,9]); + assert_eq!(*a, [0, 1]); + assert_eq!(*b, [2, 3, 4]); + assert_eq!(*c, [5, 6, 7, 8, 9]); } diff --git a/examples/simple-case.rs b/examples/simple-case.rs index 434e253..fc911ae 100644 --- a/examples/simple-case.rs +++ b/examples/simple-case.rs @@ -10,6 +10,6 @@ fn main() { x[20] = 1; x[21] = 4; x[24] = 3; - x[0] = add_three(array_mut_ref![x,20,3]); + x[0] = add_three(array_mut_ref![x, 20, 3]); assert_eq!(x[0], 8); } diff --git a/src/lib.rs b/src/lib.rs index 581c181..00e679c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,13 +62,13 @@ macro_rules! array_ref { &*(slice.as_ptr() as *const [_; $len]) } let offset = $offset; - let slice = & $arr[offset..offset + $len]; + let slice = &$arr[offset..offset + $len]; #[allow(unused_unsafe)] unsafe { as_array(slice) } } - }} + }}; } /// You can use `array_refs` to generate a series of array references @@ -174,7 +174,6 @@ macro_rules! array_refs { }} } - /// You can use `mut_array_refs` to generate a series of mutable array /// references to an input mutable array reference. The idea is if /// you want to break an array into a series of contiguous and @@ -327,210 +326,203 @@ macro_rules! array_mut_ref { as_array(slice) } } - }} + }}; } - #[allow(clippy::all)] #[cfg(test)] mod test { -extern crate quickcheck; + extern crate quickcheck; -use std::vec::Vec; + use std::vec::Vec; -// use super::*; + // use super::*; -#[test] -#[should_panic] -fn checks_bounds() { - let foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let bar = array_ref!(foo, 1, 11); - println!("I am checking that I can dereference bar[0] = {}", bar[0]); -} - -#[test] -fn simple_case_works() { - fn check(expected: [u8; 3], actual: &[u8; 3]) { - for (e, a) in (&expected).iter().zip(actual.iter()) { - assert_eq!(e, a) - } - } - let mut foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - { - let bar = array_ref!(foo, 2, 3); - check([2, 3, 4], bar); + #[test] + #[should_panic] + fn checks_bounds() { + let foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let bar = array_ref!(foo, 1, 11); + println!("I am checking that I can dereference bar[0] = {}", bar[0]); } - check([0, 1, 2], array_ref!(foo, 0, 3)); - fn zero2(x: &mut [u8; 2]) { - x[0] = 0; - x[1] = 0; - } - zero2(array_mut_ref!(foo, 8, 2)); - check([0, 0, 10], array_ref!(foo, 8, 3)); -} - -#[test] -fn check_array_ref_5() { - fn f(data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() < offset + 5 { - return quickcheck::TestResult::discard(); + #[test] + fn simple_case_works() { + fn check(expected: [u8; 3], actual: &[u8; 3]) { + for (e, a) in (&expected).iter().zip(actual.iter()) { + assert_eq!(e, a) + } } - let out = array_ref!(data, offset, 5); - quickcheck::TestResult::from_bool(out.len() == 5) - } - quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); -} - -#[test] -fn check_array_ref_out_of_bounds_5() { - fn f(data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() >= offset + 5 { - return quickcheck::TestResult::discard(); + let mut foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + { + let bar = array_ref!(foo, 2, 3); + check([2, 3, 4], bar); + } + check([0, 1, 2], array_ref!(foo, 0, 3)); + fn zero2(x: &mut [u8; 2]) { + x[0] = 0; + x[1] = 0; } - quickcheck::TestResult::must_fail(move || { - array_ref!(data, offset, 5); - }) + zero2(array_mut_ref!(foo, 8, 2)); + check([0, 0, 10], array_ref!(foo, 8, 3)); } - quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); -} -#[test] -fn check_array_mut_ref_7() { - fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() < offset + 7 { - return quickcheck::TestResult::discard(); + #[test] + fn check_array_ref_5() { + fn f(data: Vec, offset: usize) -> quickcheck::TestResult { + if data.len() < offset + 5 { + return quickcheck::TestResult::discard(); + } + let out = array_ref!(data, offset, 5); + quickcheck::TestResult::from_bool(out.len() == 5) } - let out = array_mut_ref!(data, offset, 7); - out[6] = 3; - quickcheck::TestResult::from_bool(out.len() == 7) + quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); } - quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); -} - -#[test] -fn check_array_mut_ref_out_of_bounds_32() { - fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() >= offset + 32 { - return quickcheck::TestResult::discard(); + #[test] + fn check_array_ref_out_of_bounds_5() { + fn f(data: Vec, offset: usize) -> quickcheck::TestResult { + if data.len() >= offset + 5 { + return quickcheck::TestResult::discard(); + } + quickcheck::TestResult::must_fail(move || { + array_ref!(data, offset, 5); + }) } - quickcheck::TestResult::must_fail(move || { - array_mut_ref!(data, offset, 32); - }) + quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); } - quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); -} - -#[test] -fn test_5_array_refs() { - let mut data: [usize; 128] = [0; 128]; - for i in 0..128 { - data[i] = i; + #[test] + fn check_array_mut_ref_7() { + fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { + if data.len() < offset + 7 { + return quickcheck::TestResult::discard(); + } + let out = array_mut_ref!(data, offset, 7); + out[6] = 3; + quickcheck::TestResult::from_bool(out.len() == 7) + } + quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); } - let data = data; - let (a,b,c,d,e) = array_refs!(&data, 1, 14, 3, 100, 10); - assert_eq!(a.len(), 1 as usize); - assert_eq!(b.len(), 14 as usize); - assert_eq!(c.len(), 3 as usize); - assert_eq!(d.len(), 100 as usize); - assert_eq!(e.len(), 10 as usize); - assert_eq!(a, array_ref![data, 0, 1]); - assert_eq!(b, array_ref![data, 1, 14]); - assert_eq!(c, array_ref![data, 15, 3]); - assert_eq!(e, array_ref![data, 118, 10]); -} -#[test] -fn test_5_array_refs_dotdot() { - let mut data: [usize; 128] = [0; 128]; - for i in 0..128 { - data[i] = i; + #[test] + fn check_array_mut_ref_out_of_bounds_32() { + fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { + if data.len() >= offset + 32 { + return quickcheck::TestResult::discard(); + } + quickcheck::TestResult::must_fail(move || { + array_mut_ref!(data, offset, 32); + }) + } + quickcheck::quickcheck(f as fn(Vec, usize) -> quickcheck::TestResult); } - let data = data; - let (a,b,c,d,e) = array_refs!(&data, 1, 14, 3; ..; 10); - assert_eq!(a.len(), 1 as usize); - assert_eq!(b.len(), 14 as usize); - assert_eq!(c.len(), 3 as usize); - assert_eq!(d.len(), 100 as usize); - assert_eq!(e.len(), 10 as usize); - assert_eq!(a, array_ref![data, 0, 1]); - assert_eq!(b, array_ref![data, 1, 14]); - assert_eq!(c, array_ref![data, 15, 3]); - assert_eq!(e, array_ref![data, 118, 10]); -} - -#[test] -fn test_5_mut_xarray_refs() { - let mut data: [usize; 128] = [0; 128]; - { - // temporarily borrow the data to modify it. - let (a,b,c,d,e) = mut_array_refs!(&mut data, 1, 14, 3, 100, 10); + #[test] + fn test_5_array_refs() { + let mut data: [usize; 128] = [0; 128]; + for i in 0..128 { + data[i] = i; + } + let data = data; + let (a, b, c, d, e) = array_refs!(&data, 1, 14, 3, 100, 10); assert_eq!(a.len(), 1 as usize); assert_eq!(b.len(), 14 as usize); assert_eq!(c.len(), 3 as usize); assert_eq!(d.len(), 100 as usize); assert_eq!(e.len(), 10 as usize); - *a = [1; 1]; - *b = [14; 14]; - *c = [3; 3]; - *d = [100; 100]; - *e = [10; 10]; + assert_eq!(a, array_ref![data, 0, 1]); + assert_eq!(b, array_ref![data, 1, 14]); + assert_eq!(c, array_ref![data, 15, 3]); + assert_eq!(e, array_ref![data, 118, 10]); } - assert_eq!(&[1;1], array_ref![data, 0, 1]); - assert_eq!(&[14;14], array_ref![data, 1, 14]); - assert_eq!(&[3;3], array_ref![data, 15, 3]); - assert_eq!(&[10;10], array_ref![data, 118, 10]); -} -#[test] -fn test_5_mut_xarray_refs_with_dotdot() { - let mut data: [usize; 128] = [0; 128]; - { - // temporarily borrow the data to modify it. - let (a,b,c,d,e) = mut_array_refs!(&mut data, 1, 14, 3; ..; 10); + #[test] + fn test_5_array_refs_dotdot() { + let mut data: [usize; 128] = [0; 128]; + for i in 0..128 { + data[i] = i; + } + let data = data; + let (a, b, c, d, e) = array_refs!(&data, 1, 14, 3; ..; 10); assert_eq!(a.len(), 1 as usize); assert_eq!(b.len(), 14 as usize); assert_eq!(c.len(), 3 as usize); assert_eq!(d.len(), 100 as usize); assert_eq!(e.len(), 10 as usize); - *a = [1; 1]; - *b = [14; 14]; - *c = [3; 3]; - *e = [10; 10]; + assert_eq!(a, array_ref![data, 0, 1]); + assert_eq!(b, array_ref![data, 1, 14]); + assert_eq!(c, array_ref![data, 15, 3]); + assert_eq!(e, array_ref![data, 118, 10]); } - assert_eq!(&[1;1], array_ref![data, 0, 1]); - assert_eq!(&[14;14], array_ref![data, 1, 14]); - assert_eq!(&[3;3], array_ref![data, 15, 3]); - assert_eq!(&[10;10], array_ref![data, 118, 10]); -} -#[forbid(clippy::ptr_offset_with_cast)] -#[test] -fn forbidden_clippy_lints_do_not_fire() { - let mut data = [0u8; 32]; - let _ = array_refs![&data, 8; .. ;]; - let _ = mut_array_refs![&mut data, 8; .. ; 10]; -} + #[test] + fn test_5_mut_xarray_refs() { + let mut data: [usize; 128] = [0; 128]; + { + // temporarily borrow the data to modify it. + let (a, b, c, d, e) = mut_array_refs!(&mut data, 1, 14, 3, 100, 10); + assert_eq!(a.len(), 1 as usize); + assert_eq!(b.len(), 14 as usize); + assert_eq!(c.len(), 3 as usize); + assert_eq!(d.len(), 100 as usize); + assert_eq!(e.len(), 10 as usize); + *a = [1; 1]; + *b = [14; 14]; + *c = [3; 3]; + *d = [100; 100]; + *e = [10; 10]; + } + assert_eq!(&[1; 1], array_ref![data, 0, 1]); + assert_eq!(&[14; 14], array_ref![data, 1, 14]); + assert_eq!(&[3; 3], array_ref![data, 15, 3]); + assert_eq!(&[10; 10], array_ref![data, 118, 10]); + } + + #[test] + fn test_5_mut_xarray_refs_with_dotdot() { + let mut data: [usize; 128] = [0; 128]; + { + // temporarily borrow the data to modify it. + let (a, b, c, d, e) = mut_array_refs!(&mut data, 1, 14, 3; ..; 10); + assert_eq!(a.len(), 1 as usize); + assert_eq!(b.len(), 14 as usize); + assert_eq!(c.len(), 3 as usize); + assert_eq!(d.len(), 100 as usize); + assert_eq!(e.len(), 10 as usize); + *a = [1; 1]; + *b = [14; 14]; + *c = [3; 3]; + *e = [10; 10]; + } + assert_eq!(&[1; 1], array_ref![data, 0, 1]); + assert_eq!(&[14; 14], array_ref![data, 1, 14]); + assert_eq!(&[3; 3], array_ref![data, 15, 3]); + assert_eq!(&[10; 10], array_ref![data, 118, 10]); + } -#[test] -fn single_arg_refs() { - let mut data = [0u8; 8]; - let (_, ) = array_refs![&data, 8]; - let (_, ) = mut_array_refs![&mut data, 8]; + #[forbid(clippy::ptr_offset_with_cast)] + #[test] + fn forbidden_clippy_lints_do_not_fire() { + let mut data = [0u8; 32]; + let _ = array_refs![&data, 8; .. ;]; + let _ = mut_array_refs![&mut data, 8; .. ; 10]; + } - let (_, _) = array_refs![&data, 4; ..;]; - let (_, _) = mut_array_refs![&mut data, 4; ..;]; + #[test] + fn single_arg_refs() { + let mut data = [0u8; 8]; + let (_,) = array_refs![&data, 8]; + let (_,) = mut_array_refs![&mut data, 8]; - let (_, _) = array_refs![&data,; ..; 4]; - let (_, _) = mut_array_refs![&mut data,; ..; 4]; + let (_, _) = array_refs![&data, 4; ..;]; + let (_, _) = mut_array_refs![&mut data, 4; ..;]; - let (_,) = array_refs![&data,; ..;]; - let (_,) = mut_array_refs![&mut data,; ..;]; -} + let (_, _) = array_refs![&data,; ..; 4]; + let (_, _) = mut_array_refs![&mut data,; ..; 4]; + let (_,) = array_refs![&data,; ..;]; + let (_,) = mut_array_refs![&mut data,; ..;]; + } } // mod test - From 42b8ffbf1f671d3fafa45028aebd3cf113ee46c3 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Sat, 20 Jul 2024 07:01:06 -0700 Subject: [PATCH 07/14] switch to saturating add and add explicit panic in case of overflow --- src/lib.rs | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 00e679c..7b6d4c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,29 +105,13 @@ macro_rules! array_ref { macro_rules! array_refs { ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{ { - /// A hokey struct to avoid theoretical overflow, which is only used - /// at compile time, so efficiency of the overflow checks are not of - /// concern. - struct SaturatingUsize(usize); - impl SaturatingUsize { - // It is only used at compile time, so gets incorrectly - // triggered as "dead code". - #[allow(dead_code)] - const fn add(self, rhs: usize) -> Self { - if let Some(v) = self.0.checked_add(rhs) { - SaturatingUsize(v) - } else { - SaturatingUsize(usize::MAX) - } - } - } - use core::slice; #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &[T]) -> ( $( &[T; $pre], )* &[T], $( &[T; $post], )*) { - const MIN_LEN: usize = SaturatingUsize(0) $( .add($pre) )* $( .add($post) )* .0; + const MIN_LEN: usize = 0usize $( .saturating_add($pre) )* $( .saturating_add($post) )*; + assert!(MIN_LEN < usize::MAX, "Your arrays are too big, are you trying to hack yourself?!"); let var_len = a.len() - MIN_LEN; assert!(a.len() >= MIN_LEN); let mut p = a.as_ptr(); @@ -218,29 +202,13 @@ macro_rules! array_refs { macro_rules! mut_array_refs { ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{ { - /// A hokey struct to avoid theoretical overflow, which is only used - /// at compile time, so efficiency of the overflow checks are not of - /// concern. - struct SaturatingUsize(usize); - impl SaturatingUsize { - // It is only used at compile time, so gets incorrectly - // triggered as "dead code". - #[allow(dead_code)] - const fn add(self, rhs: usize) -> Self { - if let Some(v) = self.0.checked_add(rhs) { - SaturatingUsize(v) - } else { - SaturatingUsize(usize::MAX) - } - } - } - use core::slice; #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] unsafe fn as_arrays(a: &mut [T]) -> ( $( &mut [T; $pre], )* &mut [T], $( &mut [T; $post], )*) { - const MIN_LEN: usize = SaturatingUsize(0) $( .add($pre) )* $( .add($post) )* .0; + const MIN_LEN: usize = 0usize $( .saturating_add($pre) )* $( .saturating_add($post) )*; + assert!(MIN_LEN < usize::MAX, "Your arrays are too big, are you trying to hack yourself?!"); let var_len = a.len() - MIN_LEN; assert!(a.len() >= MIN_LEN); let mut p = a.as_mut_ptr(); From fe1355e06a0ef42f91ea559ba01004b5ebec4c50 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Sat, 20 Jul 2024 15:13:13 -0700 Subject: [PATCH 08/14] bump version for soundness release --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 78dca77..de0eafd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arrayref" -version = "0.3.7" +version = "0.3.8" authors = ["David Roundy "] description = "Macros to take array references of slices" license = "BSD-2-Clause" From ad6988311cb226925449fb00dbc2e6facc8fb1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Cruz?= Date: Fri, 16 Aug 2024 12:13:03 +0200 Subject: [PATCH 09/14] fix link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10603a0..587bf9c 100644 --- a/README.md +++ b/README.md @@ -106,4 +106,4 @@ explicit. Moreover (although I have not tested this), the use of array references rather than slices *should* result in far fewer bounds checks, since almost all sizes are known at compile time. -[2]: https://github.com/droundy/onionsalt/blob/master/src/crypto.rs +[2]: https://github.com/droundy/onionsalt/blob/master/src/crypto/mod.rs From af5a9154bde9eef7475d1f622bae8851333ad336 Mon Sep 17 00:00:00 2001 From: "Benjamin A. Beasley" Date: Tue, 3 Sep 2024 10:11:29 -0400 Subject: [PATCH 10/14] Fix bounds math issues in tests revealed by quickcheck v1 Some tests relied on unsigned arithmetic that could wrap around, and quickcheck 1.0 was able to reveal the problem. All of the issues were in the tests rather than in the implementation. Fixes #22. Fixes compatibility with quickcheck v1. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7b6d4c0..1746f69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -339,7 +339,7 @@ mod test { #[test] fn check_array_ref_5() { fn f(data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() < offset + 5 { + if data.len() < 5 || data.len() - 5 < offset { return quickcheck::TestResult::discard(); } let out = array_ref!(data, offset, 5); @@ -351,7 +351,7 @@ mod test { #[test] fn check_array_ref_out_of_bounds_5() { fn f(data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() >= offset + 5 { + if data.len() >= 5 && data.len() - 5 >= offset { return quickcheck::TestResult::discard(); } quickcheck::TestResult::must_fail(move || { @@ -364,7 +364,7 @@ mod test { #[test] fn check_array_mut_ref_7() { fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() < offset + 7 { + if data.len() < 7 || data.len() - 7 < offset { return quickcheck::TestResult::discard(); } let out = array_mut_ref!(data, offset, 7); @@ -377,7 +377,7 @@ mod test { #[test] fn check_array_mut_ref_out_of_bounds_32() { fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { - if data.len() >= offset + 32 { + if data.len() >= 32 && data.len() - 32 >= offset { return quickcheck::TestResult::discard(); } quickcheck::TestResult::must_fail(move || { From e0fea6b8fc04f82d1435842ec044429c8250657e Mon Sep 17 00:00:00 2001 From: "Benjamin A. Beasley" Date: Tue, 3 Sep 2024 09:34:59 -0400 Subject: [PATCH 11/14] Use quickcheck v1 for testing --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index de0eafd..3e98c67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,4 @@ repository = "https://github.com/droundy/arrayref" documentation = "https://docs.rs/arrayref" [dev-dependencies] -quickcheck = "0.6" +quickcheck = "1.0" From fd823d5f334ed91098ffbf7f2061b53dc0765c0c Mon Sep 17 00:00:00 2001 From: "Benjamin A. Beasley" Date: Sat, 7 Sep 2024 09:39:06 -0400 Subject: [PATCH 12/14] Add explanatory comments to weird overflow-proof conditionals --- src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1746f69..c9f1013 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -339,6 +339,8 @@ mod test { #[test] fn check_array_ref_5() { fn f(data: Vec, offset: usize) -> quickcheck::TestResult { + // Compute the following, with correct results even if the sum would overflow: + // if data.len() < offset + 5 if data.len() < 5 || data.len() - 5 < offset { return quickcheck::TestResult::discard(); } @@ -351,6 +353,8 @@ mod test { #[test] fn check_array_ref_out_of_bounds_5() { fn f(data: Vec, offset: usize) -> quickcheck::TestResult { + // Compute the following, with correct results even if the sum would overflow: + // if data.len() >= offset + 5 if data.len() >= 5 && data.len() - 5 >= offset { return quickcheck::TestResult::discard(); } @@ -364,6 +368,8 @@ mod test { #[test] fn check_array_mut_ref_7() { fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { + // Compute the following, with correct results even if the sum would overflow: + // if data.len() < offset + 7 if data.len() < 7 || data.len() - 7 < offset { return quickcheck::TestResult::discard(); } @@ -377,6 +383,8 @@ mod test { #[test] fn check_array_mut_ref_out_of_bounds_32() { fn f(mut data: Vec, offset: usize) -> quickcheck::TestResult { + // Compute the following, with correct results even if the sum would overflow: + // if data.len() >= offset + 32 if data.len() >= 32 && data.len() - 32 >= offset { return quickcheck::TestResult::discard(); } From c2e1af8b1424d925bbc7ac3d2e5f3ddf292e91e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nurzhan=20Sak=C3=A9n?= Date: Fri, 13 Sep 2024 12:28:18 +0400 Subject: [PATCH 13/14] Make `array_ref` and `array_refs` usable in const fn --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7b6d4c0..b043e25 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,7 @@ macro_rules! array_ref { ($arr:expr, $offset:expr, $len:expr) => {{ { #[inline] - unsafe fn as_array(slice: &[T]) -> &[T; $len] { + const unsafe fn as_array(slice: &[T]) -> &[T; $len] { &*(slice.as_ptr() as *const [_; $len]) } let offset = $offset; @@ -109,7 +109,7 @@ macro_rules! array_refs { #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] - unsafe fn as_arrays(a: &[T]) -> ( $( &[T; $pre], )* &[T], $( &[T; $post], )*) { + const unsafe fn as_arrays(a: &[T]) -> ( $( &[T; $pre], )* &[T], $( &[T; $post], )*) { const MIN_LEN: usize = 0usize $( .saturating_add($pre) )* $( .saturating_add($post) )*; assert!(MIN_LEN < usize::MAX, "Your arrays are too big, are you trying to hack yourself?!"); let var_len = a.len() - MIN_LEN; @@ -141,7 +141,7 @@ macro_rules! array_refs { #[inline] #[allow(unused_assignments)] #[allow(clippy::eval_order_dependence)] - unsafe fn as_arrays(a: &[T; $( $len + )* 0 ]) -> ( $( &[T; $len], )* ) { + const unsafe fn as_arrays(a: &[T; $( $len + )* 0 ]) -> ( $( &[T; $len], )* ) { let mut p = a.as_ptr(); ( $( { let aref = &*(p as *const [T; $len]); From f8d0299d863922db6c409d08098941e833b70d69 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Sat, 14 Sep 2024 05:24:19 -0700 Subject: [PATCH 14/14] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3e98c67..6e1041b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arrayref" -version = "0.3.8" +version = "0.3.9" authors = ["David Roundy "] description = "Macros to take array references of slices" license = "BSD-2-Clause"