• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::alloc::{alloc, alloc_zeroed, dealloc, Layout};
6 
7 /// A contiguous memory allocation with a specified size and alignment, with a
8 /// Drop impl to perform the deallocation.
9 ///
10 /// Conceptually this is like a Box<[u8]> but for which we can select a minimum
11 /// required alignment at the time of allocation.
12 ///
13 /// # Example
14 ///
15 /// ```
16 /// use std::alloc::Layout;
17 /// use std::mem;
18 /// use sys_util::LayoutAllocation;
19 ///
20 /// #[repr(C)]
21 /// struct Header {
22 ///     q: usize,
23 ///     entries: [Entry; 0], // flexible array member
24 /// }
25 ///
26 /// #[repr(C)]
27 /// struct Entry {
28 ///     e: usize,
29 /// }
30 ///
31 /// fn demo(num_entries: usize) {
32 ///     let size = mem::size_of::<Header>() + num_entries * mem::size_of::<Entry>();
33 ///     let layout = Layout::from_size_align(size, mem::align_of::<Header>()).unwrap();
34 ///     let mut allocation = LayoutAllocation::zeroed(layout);
35 ///
36 ///     // Safe to obtain an exclusive reference because there are no other
37 ///     // references to the allocation yet and all-zero is a valid bit pattern for
38 ///     // our header.
39 ///     let header = unsafe { allocation.as_mut::<Header>() };
40 /// }
41 /// ```
42 pub struct LayoutAllocation {
43     ptr: *mut u8,
44     layout: Layout,
45 }
46 
47 impl LayoutAllocation {
48     /// Allocates memory with the specified size and alignment. The content is
49     /// not initialized.
50     ///
51     /// Uninitialized data is not safe to read. Further, it is not safe to
52     /// obtain a reference to data potentially holding a bit pattern
53     /// incompatible with its type, for example an uninitialized bool or enum.
uninitialized(layout: Layout) -> Self54     pub fn uninitialized(layout: Layout) -> Self {
55         let ptr = if layout.size() > 0 {
56             unsafe {
57                 // Safe as long as we guarantee layout.size() > 0.
58                 alloc(layout)
59             }
60         } else {
61             layout.align() as *mut u8
62         };
63         LayoutAllocation { ptr, layout }
64     }
65 
66     /// Allocates memory with the specified size and alignment and initializes
67     /// the content to all zero-bytes.
68     ///
69     /// Note that zeroing the memory does not necessarily make it safe to obtain
70     /// a reference to the allocation. Depending on the intended type T,
71     /// all-zero may or may not be a legal bit pattern for that type. For
72     /// example obtaining a reference would immediately be undefined behavior if
73     /// one of the fields has type NonZeroUsize.
zeroed(layout: Layout) -> Self74     pub fn zeroed(layout: Layout) -> Self {
75         let ptr = if layout.size() > 0 {
76             unsafe {
77                 // Safe as long as we guarantee layout.size() > 0.
78                 alloc_zeroed(layout)
79             }
80         } else {
81             layout.align() as *mut u8
82         };
83         LayoutAllocation { ptr, layout }
84     }
85 
86     /// Returns a raw pointer to the allocated data.
as_ptr<T>(&self) -> *mut T87     pub fn as_ptr<T>(&self) -> *mut T {
88         self.ptr as *mut T
89     }
90 
91     /// Returns a shared reference to the allocated data.
92     ///
93     /// # Safety
94     ///
95     /// Caller is responsible for ensuring that the data behind this pointer has
96     /// been initialized as much as necessary and that there are no already
97     /// existing mutable references to any part of the data.
as_ref<T>(&self) -> &T98     pub unsafe fn as_ref<T>(&self) -> &T {
99         &*self.as_ptr()
100     }
101 
102     /// Returns an exclusive reference to the allocated data.
103     ///
104     /// # Safety
105     ///
106     /// Caller is responsible for ensuring that the data behind this pointer has
107     /// been initialized as much as necessary and that there are no already
108     /// existing references to any part of the data.
as_mut<T>(&mut self) -> &mut T109     pub unsafe fn as_mut<T>(&mut self) -> &mut T {
110         &mut *self.as_ptr()
111     }
112 }
113 
114 impl Drop for LayoutAllocation {
drop(&mut self)115     fn drop(&mut self) {
116         if self.layout.size() > 0 {
117             unsafe {
118                 // Safe as long as we guarantee layout.size() > 0.
119                 dealloc(self.ptr, self.layout);
120             }
121         }
122     }
123 }
124