Skip to content

Commit

Permalink
safety comments, more explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Nov 12, 2024
1 parent d7c8d0f commit 1f96ed4
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 26 deletions.
45 changes: 20 additions & 25 deletions utils/zerovec/src/ule/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,33 @@ pub struct MultiFieldsULE<const LEN: usize, Format: VarZeroVecFormat>(
impl<const LEN: usize, Format: VarZeroVecFormat> MultiFieldsULE<LEN, Format> {
/// Compute the amount of bytes needed to support elements with lengths `lengths`
#[inline]
#[allow(clippy::expect_used)] // See #1410
pub fn compute_encoded_len_for(lengths: [usize; LEN]) -> usize {
#[allow(clippy::expect_used)] // See #1410
unsafe {
// safe since BlankSliceEncoder is transparent over usize
let lengths = &*(lengths.as_slice() as *const [usize] as *const [BlankSliceEncoder]);
crate::varzerovec::components::compute_serializable_len_without_length::<_, _, Format>(
lengths,
)
.expect("Too many bytes to encode") as usize
}
let lengths = lengths.map(BlankSliceEncoder);
crate::varzerovec::components::compute_serializable_len_without_length::<_, _, Format>(
&lengths,
)
.expect("Too many bytes to encode") as usize
}

/// Construct a partially initialized MultiFieldsULE backed by a mutable byte buffer
pub fn new_from_lengths_partially_initialized<'a>(
lengths: [usize; LEN],
output: &'a mut [u8],
) -> &'a mut Self {
let lengths = lengths.map(BlankSliceEncoder);
crate::varzerovec::components::write_serializable_bytes_without_length::<_, _, Format>(
&lengths, output,
);
debug_assert!(
<VarZeroLengthlessSlice<[u8], Format>>::parse_byte_slice(LEN as u32, output).is_ok(),
"Encoded slice must be valid VarZeroSlice"
);
unsafe {
// safe since BlankSliceEncoder is transparent over usize
let lengths = &*(lengths.as_slice() as *const [usize] as *const [BlankSliceEncoder]);
crate::varzerovec::components::write_serializable_bytes_without_length::<_, _, Format>(
lengths, output,
);
debug_assert!(
<VarZeroLengthlessSlice<[u8], Format>>::parse_byte_slice(LEN as u32, output)
.is_ok(),
"Encoded slice must be valid VarZeroSlice"
);
// Safe since write_serializable_bytes produces a valid VarZeroSlice buffer
// Safe since write_serializable_bytes produces a valid VarZeroLengthlessSlice buffer with the right format
let slice = <VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked_mut(output);
// safe since `Self` is transparent over VarZeroSlice
mem::transmute::<&mut VarZeroLengthlessSlice<_, Format>, &mut Self>(slice)
// safe since `Self` is transparent over VarZeroLengthlessSlice<[u8], Format>
mem::transmute::<&mut VarZeroLengthlessSlice<[u8], Format>, &mut Self>(slice)
}
}

Expand Down Expand Up @@ -97,11 +92,11 @@ impl<const LEN: usize, Format: VarZeroVecFormat> MultiFieldsULE<LEN, Format> {
/// Construct from a byte slice
///
/// # Safety
/// - byte slice must be a valid VarZeroLengthlessSlice<[u8]> with length LEN
/// - byte slice must be a valid VarZeroLengthlessSlice<[u8], Format> with length LEN
#[inline]
pub unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self {
// &Self is transparent over &VZS<..>
mem::transmute(<VarZeroLengthlessSlice<[u8]>>::from_bytes_unchecked(bytes))
// &Self is transparent over &VZS<..> with the right format
mem::transmute(<VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked(bytes))
}

/// Get the bytes behind this value
Expand Down
8 changes: 8 additions & 0 deletions utils/zerovec/src/ule/tuplevar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ macro_rules! tuple_varule {
unsafe impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> VarULE for $name<$($T,)+ Format>
{
fn validate_byte_slice(bytes: &[u8]) -> Result<(), UleError> {
// Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
// as in the type def
let multi = <MultiFieldsULE<$len, Format> as VarULE>::parse_byte_slice(bytes)?;
$(
// Safety invariant: $i < $len, from the macro invocation
Expand All @@ -82,6 +84,8 @@ macro_rules! tuple_varule {
}

unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self {
// Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
// as in the type def
let multi = <MultiFieldsULE<$len, Format> as VarULE>::from_byte_slice_unchecked(bytes);

// This type is repr(transparent) over MultiFieldsULE<$len>, so its slices can be transmuted
Expand Down Expand Up @@ -136,12 +140,16 @@ macro_rules! tuple_varule {

#[inline]
fn encode_var_ule_len(&self) -> usize {
// Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
// as in the type def
MultiFieldsULE::<$len, Format>::compute_encoded_len_for([$(self.$i.encode_var_ule_len()),+])
}

#[inline]
fn encode_var_ule_write(&self, dst: &mut [u8]) {
let lengths = [$(self.$i.encode_var_ule_len()),+];
// Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
// as in the type def
let multi = MultiFieldsULE::<$len, Format>::new_from_lengths_partially_initialized(lengths, dst);
$(
// Safety: $i < $len, from the macro invocation, and field $i is supposed to be of type $T
Expand Down
2 changes: 1 addition & 1 deletion utils/zerovec/src/varzerovec/lengthless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use core::mem;
/// Without knowing the length this is of course unsafe to use directly.
#[repr(transparent)]
#[derive(PartialEq, Eq)]
pub(crate) struct VarZeroLengthlessSlice<T: ?Sized, F = Index16> {
pub(crate) struct VarZeroLengthlessSlice<T: ?Sized, F> {
marker: PhantomData<(F, T)>,
/// The original slice this was constructed from
// Safety invariant: This field must have successfully passed through
Expand Down

0 comments on commit 1f96ed4

Please sign in to comment.