Skip to content

Commit 888cd2a

Browse files
committed
vulkan: Mark fn mapped_(mut_)slice() as unsafe
As discussed long ago, and recently in #138, it is undefined behaviour to create or transmute to `&[u8]` when the underlying data is possibly uninit. This also holds true for transmuting arbitrary `T: Copy` structures to `&[u8]` where eventual padding bytes are considered uninitialized, hence invalid for `u8`. Instead of coming up with a massive safety API that distinguishes between uninitialized and initialized buffers - which turn out to be really easy to invalidate by copying structures with padding bytes - place the onus on the user to keep track of initialization status by only ever providing mapped slices in an `unsafe` context. Users are expected to initialize the buffer using `ptr::copy(_nonoverlapping)()` when used from a CPU context instead of calling `.mapped_mut_slice()`, or switch to the new [presser] API from #138. [presser]: https://crates.io/crates/presser
1 parent b92f7cc commit 888cd2a

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

src/vulkan/mod.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,24 @@ impl Allocation {
9292

9393
/// Returns a valid mapped slice if the memory is host visible, otherwise it will return None.
9494
/// The slice already references the exact memory region of the allocation, so no offset needs to be applied.
95-
pub fn mapped_slice(&self) -> Option<&[u8]> {
96-
self.mapped_ptr().map(|ptr| unsafe {
97-
std::slice::from_raw_parts(ptr.cast().as_ptr(), self.size as usize)
98-
})
95+
///
96+
/// # Safety
97+
/// Only to be called when the memory is known to be _fully_ initialized.
98+
pub unsafe fn mapped_slice(&self) -> Option<&[u8]> {
99+
self.mapped_ptr()
100+
.map(|ptr| std::slice::from_raw_parts(ptr.cast().as_ptr(), self.size as usize))
99101
}
100102

101103
/// Returns a valid mapped mutable slice if the memory is host visible, otherwise it will return None.
102104
/// The slice already references the exact memory region of the allocation, so no offset needs to be applied.
103-
pub fn mapped_slice_mut(&mut self) -> Option<&mut [u8]> {
104-
self.mapped_ptr().map(|ptr| unsafe {
105-
std::slice::from_raw_parts_mut(ptr.cast().as_ptr(), self.size as usize)
106-
})
105+
///
106+
/// # Safety
107+
/// Only to be called when the memory is known to be _fully_ initialized. Use [`std::ptr::copy()`] or
108+
/// [`std::ptr::copy_nonoverlapping()`] on [`mapped_ptr()`][Self::mapped_ptr()] to initialize this buffer
109+
/// from the CPU instead.
110+
pub unsafe fn mapped_mut_slice(&mut self) -> Option<&mut [u8]> {
111+
self.mapped_ptr()
112+
.map(|ptr| std::slice::from_raw_parts_mut(ptr.cast().as_ptr(), self.size as usize))
107113
}
108114

109115
pub fn is_null(&self) -> bool {

0 commit comments

Comments
 (0)