From 0a5edd2a45b3d868e230ca6bda1efa0a3465f281 Mon Sep 17 00:00:00 2001 From: CodesInChaos Date: Sun, 19 Mar 2023 12:42:42 +0100 Subject: [PATCH] Add debug assertions related to safety conditions --- src/context/cdf_context.rs | 10 ++++++++++ src/dist.rs | 3 +++ src/lrf.rs | 6 ++++++ src/util/align.rs | 2 +- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/context/cdf_context.rs b/src/context/cdf_context.rs index e7e0cd1993..c2894683e8 100644 --- a/src/context/cdf_context.rs +++ b/src/context/cdf_context.rs @@ -611,6 +611,11 @@ impl let dst = self.data.as_mut_ptr().add(len) as *mut u16; let base = fc as *mut _ as *mut u8; let src = base.add(cdf.offset) as *const u16; + // When CDF_LEN + 1 < CDF_LEN_MAX_PLUS_1, this reads beyond the end of + // the slice described by `cdf`. + // Since it is part of `CDFContext`, the out-of-bounds data is valid. + // We conform to the stacked-borrows memory model by holding a mutable + // ref to the containing data structure. dst.copy_from_nonoverlapping(src, CDF_LEN_MAX_PLUS_1 - 1); *dst.add(CDF_LEN_MAX_PLUS_1 - 1) = cdf.offset as u16; self.data.set_len(new_len); @@ -630,10 +635,15 @@ impl unsafe { let mut src = self.data.as_mut_ptr().add(len); while len > checkpoint { + // As checkpoint is unsigned, len > 0 is implied. len -= 1; src = src.sub(1); let src = src as *mut u16; let offset = *src.add(CDF_LEN_MAX_PLUS_1 - 1) as usize; + debug_assert!( + offset + (CDF_LEN_MAX_PLUS_1 - 1) * mem::size_of::() + <= mem::size_of::() + ); let dst = base.add(offset) as *mut u16; dst.copy_from_nonoverlapping(src, CDF_LEN_MAX_PLUS_1 - 1); } diff --git a/src/dist.rs b/src/dist.rs index 4b5536a841..680cdbdfe3 100644 --- a/src/dist.rs +++ b/src/dist.rs @@ -142,11 +142,13 @@ pub(crate) mod rust { // SAFETY: The length of data must be 16. unsafe fn hadamard4x4(data: &mut [i32]) { + debug_assert_eq!(data.len(), 16); hadamard2d::<{ 4 * 4 }, 4, 4>(&mut *(data.as_mut_ptr() as *mut [i32; 16])); } // SAFETY: The length of data must be 64. unsafe fn hadamard8x8(data: &mut [i32]) { + debug_assert_eq!(data.len(), 64); hadamard2d::<{ 8 * 8 }, 8, 8>(&mut *(data.as_mut_ptr() as *mut [i32; 64])); } @@ -166,6 +168,7 @@ pub(crate) mod rust { // Size of hadamard transform should be 4x4 or 8x8 // 4x* and *x4 use 4x4 and all other use 8x8 let size: usize = w.min(h).min(8); + debug_assert!(size == 4 || size == 8); let tx2d = if size == 4 { hadamard4x4 } else { hadamard8x8 }; let mut sum: u64 = 0; diff --git a/src/lrf.rs b/src/lrf.rs index 746e411c5f..87e47a8282 100644 --- a/src/lrf.rs +++ b/src/lrf.rs @@ -194,7 +194,9 @@ pub(crate) mod rust { let ssq = get_integral_square(iimg_sq, iimg_stride, x, y, d); let (reta, retb) = sgrproj_sum_finish::(ssq, sum, n as u32, one_over_n, s); + debug_assert!(x < af.len()); *af.get_unchecked_mut(x) = reta; + debug_assert!(x < bf.len()); *bf.get_unchecked_mut(x) = retb; } } @@ -369,9 +371,13 @@ unsafe fn get_integral_square( iimg: &[u32], stride: usize, x: usize, y: usize, size: usize, ) -> u32 { // Cancel out overflow in iimg by using wrapping arithmetic + debug_assert!(y * stride + x < iimg.len()); let top_left = *iimg.get_unchecked(y * stride + x); + debug_assert!(y * stride + x + size < iimg.len()); let top_right = *iimg.get_unchecked(y * stride + x + size); + debug_assert!((y + size) * stride + x < iimg.len()); let bottom_left = *iimg.get_unchecked((y + size) * stride + x); + debug_assert!((y + size) * stride + x + size < iimg.len()); let bottom_right = *iimg.get_unchecked((y + size) * stride + x + size); top_left .wrapping_add(bottom_right) diff --git a/src/util/align.rs b/src/util/align.rs index c86424e8b2..5a16dc0d33 100644 --- a/src/util/align.rs +++ b/src/util/align.rs @@ -61,7 +61,7 @@ impl AlignedBoxedSlice { } const fn layout(len: usize) -> Layout { - // SAFETY: We are ensuring that `align` is non-zero and is a multiple of 2. + // SAFETY: We are ensuring that `align` is non-zero and is a power of 2. unsafe { Layout::from_size_align_unchecked( len * mem::size_of::(),