diff options
author | David Tolnay <dtolnay@chromium.org> | 2019-04-12 16:57:48 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-18 19:51:29 -0700 |
commit | 4b292afafcd44ca3fc34f483a8edb455a3212cb5 (patch) | |
tree | 868bdb3122e088e33836cd48608d23518ee5a1d0 /sys_util | |
parent | dc4effa72b214bc3bd14ca2f7772ab1b728aef5b (diff) | |
download | crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.tar crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.tar.gz crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.tar.bz2 crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.tar.lz crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.tar.xz crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.tar.zst crosvm-4b292afafcd44ca3fc34f483a8edb455a3212cb5.zip |
clippy: Resolve cast_ptr_alignment
This CL fixes four cases of what I believe are undefined behavior: - In vhost where the original code allocates a Vec<u8> with 1-byte alignment and casts the Vec's data pointer to a &mut vhost_memory which is required to be 8-byte aligned. Underaligned references of type &T or &mut T are always undefined behavior in Rust. - Same pattern in x86_64. - Same pattern in plugin::vcpu. - Code in crosvm_plugin that dereferences a potentially underaligned pointer. This is always undefined behavior in Rust. TEST=bin/clippy TEST=cargo test sys_util Change-Id: I926f17b1fe022a798f69d738f9990d548f40c59b Reviewed-on: https://chromium-review.googlesource.com/1566736 Commit-Ready: David Tolnay <dtolnay@chromium.org> Tested-by: David Tolnay <dtolnay@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: David Tolnay <dtolnay@chromium.org>
Diffstat (limited to 'sys_util')
-rw-r--r-- | sys_util/src/alloc.rs | 119 | ||||
-rw-r--r-- | sys_util/src/lib.rs | 2 |
2 files changed, 121 insertions, 0 deletions
diff --git a/sys_util/src/alloc.rs b/sys_util/src/alloc.rs new file mode 100644 index 0000000..ad73065 --- /dev/null +++ b/sys_util/src/alloc.rs @@ -0,0 +1,119 @@ +use std::alloc::{alloc, alloc_zeroed, dealloc, Layout}; + +/// A contiguous memory allocation with a specified size and alignment, with a +/// Drop impl to perform the deallocation. +/// +/// Conceptually this is like a Box<[u8]> but for which we can select a minimum +/// required alignment at the time of allocation. +/// +/// # Example +/// +/// ``` +/// use std::alloc::Layout; +/// use std::mem; +/// use sys_util::LayoutAllocation; +/// +/// #[repr(C)] +/// struct Header { +/// q: usize, +/// entries: [Entry; 0], // flexible array member +/// } +/// +/// #[repr(C)] +/// struct Entry { +/// e: usize, +/// } +/// +/// fn demo(num_entries: usize) { +/// let size = mem::size_of::<Header>() + num_entries * mem::size_of::<Entry>(); +/// let layout = Layout::from_size_align(size, mem::align_of::<Header>()).unwrap(); +/// let mut allocation = LayoutAllocation::zeroed(layout); +/// +/// // Safe to obtain an exclusive reference because there are no other +/// // references to the allocation yet and all-zero is a valid bit pattern for +/// // our header. +/// let header = unsafe { allocation.as_mut::<Header>() }; +/// } +/// ``` +pub struct LayoutAllocation { + ptr: *mut u8, + layout: Layout, +} + +impl LayoutAllocation { + /// Allocates memory with the specified size and alignment. The content is + /// not initialized. + /// + /// Uninitialized data is not safe to read. Further, it is not safe to + /// obtain a reference to data potentially holding a bit pattern + /// incompatible with its type, for example an uninitialized bool or enum. + pub fn uninitialized(layout: Layout) -> Self { + let ptr = if layout.size() > 0 { + unsafe { + // Safe as long as we guarantee layout.size() > 0. + alloc(layout) + } + } else { + layout.align() as *mut u8 + }; + LayoutAllocation { ptr, layout } + } + + /// Allocates memory with the specified size and alignment and initializes + /// the content to all zero-bytes. + /// + /// Note that zeroing the memory does not necessarily make it safe to obtain + /// a reference to the allocation. Depending on the intended type T, + /// all-zero may or may not be a legal bit pattern for that type. For + /// example obtaining a reference would immediately be undefined behavior if + /// one of the fields has type NonZeroUsize. + pub fn zeroed(layout: Layout) -> Self { + let ptr = if layout.size() > 0 { + unsafe { + // Safe as long as we guarantee layout.size() > 0. + alloc_zeroed(layout) + } + } else { + layout.align() as *mut u8 + }; + LayoutAllocation { ptr, layout } + } + + /// Returns a raw pointer to the allocated data. + pub fn as_ptr<T>(&self) -> *mut T { + self.ptr as *mut T + } + + /// Returns a shared reference to the allocated data. + /// + /// # Safety + /// + /// Caller is responsible for ensuring that the data behind this pointer has + /// been initialized as much as necessary and that there are no already + /// existing mutable references to any part of the data. + pub unsafe fn as_ref<T>(&self) -> &T { + &*self.as_ptr() + } + + /// Returns an exclusive reference to the allocated data. + /// + /// # Safety + /// + /// Caller is responsible for ensuring that the data behind this pointer has + /// been initialized as much as necessary and that there are no already + /// existing references to any part of the data. + pub unsafe fn as_mut<T>(&mut self) -> &mut T { + &mut *self.as_ptr() + } +} + +impl Drop for LayoutAllocation { + fn drop(&mut self) { + if self.layout.size() > 0 { + unsafe { + // Safe as long as we guarantee layout.size() > 0. + dealloc(self.ptr, self.layout); + } + } + } +} diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs index a1dffea..e2942af 100644 --- a/sys_util/src/lib.rs +++ b/sys_util/src/lib.rs @@ -5,6 +5,7 @@ //! Small system utility modules for usage by other modules. pub mod affinity; +mod alloc; #[macro_use] pub mod handle_eintr; #[macro_use] @@ -38,6 +39,7 @@ mod timerfd; mod write_zeroes; pub use crate::affinity::*; +pub use crate::alloc::LayoutAllocation; pub use crate::capabilities::drop_capabilities; pub use crate::clock::{Clock, FakeClock}; use crate::errno::errno_result; |