script: remove `unsafe` marker from slice-to-script conversions

The length of the slices is not a safety invariant.

Fairly large diff because I had to remove a bunch of `unsafe` blocks
around calls to this function.

Fixes #3531
This commit is contained in:
Andrew Poelstra 2024-11-02 13:39:45 +00:00
parent 60841f689f
commit 4431df18fe
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 16 additions and 32 deletions

View File

@ -47,32 +47,25 @@ mod primitive {
impl PushBytes { impl PushBytes {
/// Creates `&PushBytes` without checking the length. /// Creates `&PushBytes` without checking the length.
/// ///
/// # Safety
///
/// The caller is responsible for checking that the length is less than the 2^32. /// The caller is responsible for checking that the length is less than the 2^32.
unsafe fn from_slice_unchecked(bytes: &[u8]) -> &Self { fn from_slice_unchecked(bytes: &[u8]) -> &Self {
// SAFETY: The caller must guarantee that bytes.len() < 2^32. // SAFETY: The conversion is sound because &[u8] and &PushBytes
// If that is the case the conversion is sound because &[u8] and &PushBytes
// have the same layout (because of #[repr(transparent)] on PushBytes). // have the same layout (because of #[repr(transparent)] on PushBytes).
&*(bytes as *const [u8] as *const PushBytes) unsafe { &*(bytes as *const [u8] as *const PushBytes) }
} }
/// Creates `&mut PushBytes` 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 2^32. /// 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 { fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self {
// SAFETY: The caller must guarantee that bytes.len() < 2^32. // SAFETY: The conversion is sound because &mut [u8] and &mut PushBytes
// 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). // have the same layout (because of #[repr(transparent)] on PushBytes).
&mut *(bytes as *mut [u8] as *mut PushBytes) unsafe { &mut *(bytes as *mut [u8] as *mut PushBytes) }
} }
/// Creates an empty `&PushBytes`. /// Creates an empty `&PushBytes`.
pub fn empty() -> &'static Self { pub fn empty() -> &'static Self {
// SAFETY: 0 < 2^32. Self::from_slice_unchecked(&[])
unsafe { Self::from_slice_unchecked(&[]) }
} }
/// Returns the underlying bytes. /// Returns the underlying bytes.
@ -91,23 +84,17 @@ mod primitive {
#[inline] #[inline]
#[track_caller] #[track_caller]
fn index(&self, index: $type) -> &Self::Output { fn index(&self, index: $type) -> &Self::Output {
// SAFETY: Slicing can not make slices longer.
unsafe {
Self::from_slice_unchecked(&self.0[index]) Self::from_slice_unchecked(&self.0[index])
} }
} }
}
impl IndexMut<$type> for PushBytes { impl IndexMut<$type> for PushBytes {
#[inline] #[inline]
#[track_caller] #[track_caller]
fn index_mut(&mut self, index: $type) -> &mut Self::Output { 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]) Self::from_mut_slice_unchecked(&mut self.0[index])
} }
} }
}
)* )*
} }
} }
@ -141,8 +128,7 @@ mod primitive {
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
check_limit(bytes.len())?; check_limit(bytes.len())?;
// SAFETY: We've just checked the length. Ok(PushBytes::from_slice_unchecked(bytes))
Ok(unsafe { PushBytes::from_slice_unchecked(bytes) })
} }
} }
@ -151,8 +137,7 @@ mod primitive {
fn try_from(bytes: &'a mut [u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &'a mut [u8]) -> Result<Self, Self::Error> {
check_limit(bytes.len())?; check_limit(bytes.len())?;
// SAFETY: We've just checked the length. Ok(PushBytes::from_mut_slice_unchecked(bytes))
Ok(unsafe { PushBytes::from_mut_slice_unchecked(bytes) })
} }
} }
@ -163,16 +148,15 @@ mod primitive {
fn from(bytes: &'a [u8; $len]) -> Self { fn from(bytes: &'a [u8; $len]) -> Self {
// Check that the macro wasn't called with a wrong number. // Check that the macro wasn't called with a wrong number.
const _: () = [(); 1][($len >= 0x100000000u64) as usize]; const _: () = [(); 1][($len >= 0x100000000u64) as usize];
// SAFETY: We know the size of array statically and we checked macro input. PushBytes::from_slice_unchecked(bytes)
unsafe { PushBytes::from_slice_unchecked(bytes) }
} }
} }
impl<'a> From<&'a mut [u8; $len]> for &'a mut PushBytes { impl<'a> From<&'a mut [u8; $len]> for &'a mut PushBytes {
fn from(bytes: &'a mut [u8; $len]) -> Self { fn from(bytes: &'a mut [u8; $len]) -> Self {
// Macro check already above, no need to duplicate. // Macro check already above, no need to duplicate.
// SAFETY: We know the size of array statically and we checked macro input. // We know the size of array statically and we checked macro input.
unsafe { PushBytes::from_mut_slice_unchecked(bytes) } PushBytes::from_mut_slice_unchecked(bytes)
} }
} }
@ -273,13 +257,13 @@ mod primitive {
/// Extracts `PushBytes` slice /// Extracts `PushBytes` slice
pub fn as_push_bytes(&self) -> &PushBytes { pub fn as_push_bytes(&self) -> &PushBytes {
// length guaranteed by our invariant // length guaranteed by our invariant
unsafe { PushBytes::from_slice_unchecked(&self.0) } PushBytes::from_slice_unchecked(&self.0)
} }
/// Extracts mutable `PushBytes` slice /// Extracts mutable `PushBytes` slice
pub fn as_mut_push_bytes(&mut self) -> &mut PushBytes { pub fn as_mut_push_bytes(&mut self) -> &mut PushBytes {
// length guaranteed by our invariant // length guaranteed by our invariant
unsafe { PushBytes::from_mut_slice_unchecked(&mut self.0) } PushBytes::from_mut_slice_unchecked(&mut self.0)
} }
/// Accesses inner `Vec` - provided for `super` to impl other methods. /// Accesses inner `Vec` - provided for `super` to impl other methods.