Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.

Commit d9672c3

Browse files
committed
simplify two unsafes with zerocopy
Signed-off-by: Julian Schindel <mail@arctic-alpaca.de>
1 parent c336d19 commit d9672c3

1 file changed

Lines changed: 51 additions & 34 deletions

File tree

src/volatile_memory.rs

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use std::ptr::copy;
3434
use std::ptr::{read_volatile, write_volatile};
3535
use std::result;
3636
use std::sync::atomic::Ordering;
37-
use zerocopy::{FromBytes, FromZeros, IntoBytes};
37+
use zerocopy::{CastError, FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout};
3838

3939
use crate::atomic_integer::AtomicInteger;
4040
use crate::bitmap::{Bitmap, BitmapSlice, BS};
@@ -206,27 +206,36 @@ pub trait VolatileMemory {
206206
///
207207
/// If the resulting pointer is not aligned, this method will return an
208208
/// [`Error`](enum.Error.html).
209-
unsafe fn aligned_as_ref<T: Copy + Send + Sync + FromBytes + IntoBytes + FromZeros>(
209+
unsafe fn aligned_as_ref<
210+
T: Copy + Send + Sync + FromBytes + IntoBytes + FromZeros + Immutable + KnownLayout,
211+
>(
210212
&self,
211213
offset: usize,
212214
) -> Result<&T> {
213215
let slice = self.get_slice(offset, size_of::<T>())?;
214-
slice.check_alignment(align_of::<T>())?;
215-
216-
assert_eq!(
217-
slice.len(),
218-
size_of::<T>(),
219-
"VolatileMemory::get_slice(offset, count) returned slice of length != count."
220-
);
221216

222-
// SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
223-
// slice.addr is valid memory of size slice.len(). The assert above ensures that
224-
// the length of the slice is exactly enough to hold one `T`.
225-
// Dereferencing the pointer is safe because we check the alignment above, and the invariants
226-
// of this function ensure that no aliasing pointers exist. Lastly, the lifetime of the
227-
// returned VolatileArrayRef match that of the VolatileSlice returned by get_slice and thus the
228-
// lifetime one `self`.
229-
unsafe { Ok(&*(slice.addr as *const T)) }
217+
let slice_addr = slice.addr;
218+
let size_of_t = size_of::<T>();
219+
220+
// SAFETY: Creating a byte slice from the pointer is safe because the invariants of the
221+
// constructors of VolatileSlice ensure that slice.addr is valid memory of size slice.len()
222+
// and the invariants of this function ensure that no aliasing reference exists.
223+
// Lastly, the lifetime of the returned reference matches that of the VolatileSlice returned
224+
// by get_slice and thus the lifetime one `self`.
225+
let rust_slice = unsafe { core::slice::from_raw_parts(slice_addr, size_of_t) };
226+
T::ref_from_bytes(rust_slice).map_err(|error| match error {
227+
CastError::<_, T>::Alignment(_) => Error::Misaligned {
228+
addr: slice.addr.addr(),
229+
alignment: align_of::<T>(),
230+
},
231+
CastError::<_, T>::Size(size) => {
232+
panic!("VolatileMemory::get_slice({}, count) returned slice of length != count, expected: \"{}\" actual: \"{}\".", offset, size_of::<T>(), size.into_src().len());
233+
}
234+
CastError::<_, T>::Validity(infallible) => {
235+
// Ensures this error is actually infallible.
236+
match infallible {}
237+
}
238+
})
230239
}
231240

232241
/// Returns a mutable reference to an instance of `T` at `offset`. Mutable accesses performed
@@ -245,28 +254,36 @@ pub trait VolatileMemory {
245254
// the function is unsafe, and the conversion is safe if following the safety
246255
// instrutions above
247256
#[allow(clippy::mut_from_ref)]
248-
unsafe fn aligned_as_mut<T: Copy + Send + Sync + FromBytes + IntoBytes + FromZeros>(
257+
unsafe fn aligned_as_mut<
258+
T: Copy + Send + Sync + FromBytes + IntoBytes + FromZeros + KnownLayout,
259+
>(
249260
&self,
250261
offset: usize,
251262
) -> Result<&mut T> {
252263
let slice = self.get_slice(offset, size_of::<T>())?;
253-
slice.check_alignment(align_of::<T>())?;
254-
255-
assert_eq!(
256-
slice.len(),
257-
size_of::<T>(),
258-
"VolatileMemory::get_slice(offset, count) returned slice of length != count."
259-
);
260-
261-
// SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
262-
// slice.addr is valid memory of size slice.len(). The assert above ensures that
263-
// the length of the slice is exactly enough to hold one `T`.
264-
// Dereferencing the pointer is safe because we check the alignment above, and the invariants
265-
// of this function ensure that no aliasing pointers exist. Lastly, the lifetime of the
266-
// returned VolatileArrayRef match that of the VolatileSlice returned by get_slice and thus the
267-
// lifetime one `self`.
268264

269-
unsafe { Ok(&mut *(slice.addr as *mut T)) }
265+
let slice_addr = slice.addr;
266+
let size_of_t = size_of::<T>();
267+
268+
// SAFETY: Creating a mutable byte slice from the pointer is safe because the invariants of the
269+
// constructors of VolatileSlice ensure that slice.addr is valid memory of size slice.len()
270+
// and the invariants of this function ensure that no aliasing reference exists.
271+
// Lastly, the lifetime of the returned reference matches that of the VolatileSlice returned
272+
// by get_slice and thus the lifetime one `self`.
273+
let rust_slice = unsafe { core::slice::from_raw_parts_mut(slice_addr, size_of_t) };
274+
T::mut_from_bytes(rust_slice).map_err(|error| match error {
275+
CastError::<_, T>::Alignment(_) => Error::Misaligned {
276+
addr: slice.addr.addr(),
277+
alignment: align_of::<T>(),
278+
},
279+
CastError::<_, T>::Size(size) => {
280+
panic!("VolatileMemory::get_slice({}, count) returned slice of length != count, expected: \"{}\" actual: \"{}\".", offset, size_of::<T>(), size.into_src().len());
281+
}
282+
CastError::<_, T>::Validity(infallible) => {
283+
// Ensures this error is actually infallible.
284+
match infallible {}
285+
}
286+
})
270287
}
271288

272289
/// Returns a reference to an instance of `T` at `offset`. Mutable accesses performed

0 commit comments

Comments
 (0)