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