From 71d760b3f24a118fbe0dc2c7afc6cc893be40cef Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Sun, 11 Aug 2024 21:55:15 +0200 Subject: [PATCH 1/2] Add and fix documentation on PushBytes's functions --- bitcoin/src/blockdata/script/push_bytes.rs | 31 +++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/bitcoin/src/blockdata/script/push_bytes.rs b/bitcoin/src/blockdata/script/push_bytes.rs index 039b2214d1..47c1e4d97e 100644 --- a/bitcoin/src/blockdata/script/push_bytes.rs +++ b/bitcoin/src/blockdata/script/push_bytes.rs @@ -43,48 +43,53 @@ mod primitive { pub struct PushBytes([u8]); impl PushBytes { - /// Creates `&Self` without checking the length. + /// Creates `&PushBytes` without checking the length. /// /// # Safety /// - /// The caller is responsible for checking that the length is less than the [`LIMIT`]. + /// The caller is responsible for checking that the length is less than the 2^32. unsafe fn from_slice_unchecked(bytes: &[u8]) -> &Self { + // SAFETY: The caller must guarantee that bytes.len() < 2^32. + // If that is the case the conversion is sound because &[u8] and &PushBytes + // have the same layout (because of #[repr(transparent)] on PushBytes). &*(bytes as *const [u8] as *const PushBytes) } - /// Creates `&mut Self` without checking the length. + /// Creates `&mut PushBytes` without checking the length. /// /// # Safety /// - /// The caller is responsible for checking that the length is less than the [`LIMIT`]. + /// The caller is responsible for checking that the length is less than the 2^32. unsafe fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self { + // SAFETY: The caller must guarantee that bytes.len() < 2^32. + // If that is the case the conversion is sound because &mut [u8] and &mut PushBytes + // have the same layout (because of #[repr(transparent)] on PushBytes). &mut *(bytes as *mut [u8] as *mut PushBytes) } - /// Creates an empty `PushBytes`. + /// Creates an empty `&PushBytes`. pub fn empty() -> &'static Self { - // 0 < LIMIT + // SAFETY: 0 < 2^32. unsafe { Self::from_slice_unchecked(&[]) } } /// Returns the underlying bytes. pub fn as_bytes(&self) -> &[u8] { &self.0 } - /// Returns the underlying mutbale bytes. + /// Returns the underlying mutable bytes. pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 } } macro_rules! delegate_index { ($($type:ty),* $(,)?) => { $( - /// Script subslicing operation - read [slicing safety](#slicing-safety)! impl Index<$type> for PushBytes { type Output = Self; #[inline] #[track_caller] fn index(&self, index: $type) -> &Self::Output { - // Slicing can not make slices longer + // SAFETY: Slicing can not make slices longer. unsafe { Self::from_slice_unchecked(&self.0[index]) } @@ -117,7 +122,7 @@ mod primitive { fn try_from(bytes: &'a [u8]) -> Result { check_limit(bytes.len())?; - // We've just checked the length + // SAFETY: We've just checked the length. Ok(unsafe { PushBytes::from_slice_unchecked(bytes) }) } } @@ -127,7 +132,7 @@ mod primitive { fn try_from(bytes: &'a mut [u8]) -> Result { check_limit(bytes.len())?; - // We've just checked the length + // SAFETY: We've just checked the length. Ok(unsafe { PushBytes::from_mut_slice_unchecked(bytes) }) } } @@ -139,7 +144,7 @@ mod primitive { fn from(bytes: &'a [u8; $len]) -> Self { // Check that the macro wasn't called with a wrong number. const _: () = [(); 1][($len >= 0x100000000u64) as usize]; - // We know the size of array statically and we checked macro input. + // SAFETY: We know the size of array statically and we checked macro input. unsafe { PushBytes::from_slice_unchecked(bytes) } } } @@ -147,7 +152,7 @@ mod primitive { impl<'a> From<&'a mut [u8; $len]> for &'a mut PushBytes { fn from(bytes: &'a mut [u8; $len]) -> Self { // Macro check already above, no need to duplicate. - // We know the size of array statically and we checked macro input. + // SAFETY: We know the size of array statically and we checked macro input. unsafe { PushBytes::from_mut_slice_unchecked(bytes) } } } From 7c8601a69614df342826a52c0937e2beee1068d3 Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Sun, 11 Aug 2024 21:57:20 +0200 Subject: [PATCH 2/2] implement IndexMut for PushBytes --- bitcoin/src/blockdata/script/push_bytes.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/bitcoin/src/blockdata/script/push_bytes.rs b/bitcoin/src/blockdata/script/push_bytes.rs index 47c1e4d97e..89cbdc2682 100644 --- a/bitcoin/src/blockdata/script/push_bytes.rs +++ b/bitcoin/src/blockdata/script/push_bytes.rs @@ -15,7 +15,8 @@ pub use self::primitive::*; /// break invariants. Therefore auditing this module should be sufficient. mod primitive { use core::ops::{ - Bound, Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, + Bound, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, + RangeToInclusive, }; use super::PushBytesError; @@ -95,6 +96,17 @@ mod primitive { } } } + + impl IndexMut<$type> for PushBytes { + #[inline] + #[track_caller] + fn index_mut(&mut self, index: $type) -> &mut Self::Output { + // SAFETY: Slicing can not make slices longer. + unsafe { + Self::from_mut_slice_unchecked(&mut self.0[index]) + } + } + } )* } } @@ -117,6 +129,12 @@ mod primitive { fn index(&self, index: usize) -> &Self::Output { &self.0[index] } } + impl IndexMut for PushBytes { + #[inline] + #[track_caller] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.0[index] } + } + impl<'a> TryFrom<&'a [u8]> for &'a PushBytes { type Error = PushBytesError;