summary refs log tree commit diff
path: root/sys_util
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@chromium.org>2019-04-12 16:57:48 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-04-18 19:51:29 -0700
commit4b292afafcd44ca3fc34f483a8edb455a3212cb5 (patch)
tree868bdb3122e088e33836cd48608d23518ee5a1d0 /sys_util
parentdc4effa72b214bc3bd14ca2f7772ab1b728aef5b (diff)
downloadcrosvm-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.rs119
-rw-r--r--sys_util/src/lib.rs2
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;