miri/alloc/
alloc_bytes.rs1use std::alloc::Layout;
2use std::borrow::Cow;
3use std::{alloc, slice};
4#[cfg(target_os = "linux")]
5use std::{cell::RefCell, rc::Rc};
6
7use rustc_abi::{Align, Size};
8use rustc_middle::mir::interpret::AllocBytes;
9
10#[cfg(target_os = "linux")]
11use crate::alloc::isolated_alloc::IsolatedAlloc;
12use crate::helpers::ToU64 as _;
13
14#[derive(Clone, Debug)]
15pub enum MiriAllocParams {
16 Global,
17 #[cfg(target_os = "linux")]
18 Isolated(Rc<RefCell<IsolatedAlloc>>),
19}
20
21#[derive(Debug)]
24pub struct MiriAllocBytes {
25 layout: alloc::Layout,
27 ptr: *mut u8,
32 params: MiriAllocParams,
35}
36
37impl Clone for MiriAllocBytes {
38 fn clone(&self) -> Self {
39 let bytes: Cow<'_, [u8]> = Cow::Borrowed(self);
40 let align = Align::from_bytes(self.layout.align().to_u64()).unwrap();
41 MiriAllocBytes::from_bytes(bytes, align, self.params.clone())
42 }
43}
44
45impl Drop for MiriAllocBytes {
46 fn drop(&mut self) {
47 let alloc_layout = if self.layout.size() == 0 {
50 Layout::from_size_align(1, self.layout.align()).unwrap()
51 } else {
52 self.layout
53 };
54
55 unsafe {
57 match self.params.clone() {
58 MiriAllocParams::Global => alloc::dealloc(self.ptr, alloc_layout),
59 #[cfg(target_os = "linux")]
60 MiriAllocParams::Isolated(alloc) =>
61 alloc.borrow_mut().dealloc(self.ptr, alloc_layout),
62 }
63 }
64 }
65}
66
67impl std::ops::Deref for MiriAllocBytes {
68 type Target = [u8];
69
70 fn deref(&self) -> &Self::Target {
71 unsafe { slice::from_raw_parts(self.ptr, self.layout.size()) }
74 }
75}
76
77impl std::ops::DerefMut for MiriAllocBytes {
78 fn deref_mut(&mut self) -> &mut Self::Target {
79 unsafe { slice::from_raw_parts_mut(self.ptr, self.layout.size()) }
82 }
83}
84
85impl MiriAllocBytes {
86 fn alloc_with(
90 size: u64,
91 align: u64,
92 params: MiriAllocParams,
93 alloc_fn: impl FnOnce(Layout, &MiriAllocParams) -> *mut u8,
94 ) -> Result<MiriAllocBytes, ()> {
95 let size = usize::try_from(size).map_err(|_| ())?;
96 let align = usize::try_from(align).map_err(|_| ())?;
97 let layout = Layout::from_size_align(size, align).map_err(|_| ())?;
98 let alloc_layout =
100 if size == 0 { Layout::from_size_align(1, align).unwrap() } else { layout };
101 let ptr = alloc_fn(alloc_layout, ¶ms);
102 if ptr.is_null() {
103 Err(())
104 } else {
105 Ok(Self { ptr, layout, params })
107 }
108 }
109}
110
111impl AllocBytes for MiriAllocBytes {
112 type AllocParams = MiriAllocParams;
113
114 fn from_bytes<'a>(
115 slice: impl Into<Cow<'a, [u8]>>,
116 align: Align,
117 params: MiriAllocParams,
118 ) -> Self {
119 let slice = slice.into();
120 let size = slice.len();
121 let align = align.bytes();
122 let alloc_fn = |layout, params: &MiriAllocParams| unsafe {
124 match params {
125 MiriAllocParams::Global => alloc::alloc(layout),
126 #[cfg(target_os = "linux")]
127 MiriAllocParams::Isolated(alloc) => alloc.borrow_mut().alloc(layout),
128 }
129 };
130 let alloc_bytes = MiriAllocBytes::alloc_with(size.to_u64(), align, params, alloc_fn)
131 .unwrap_or_else(|()| {
132 panic!("Miri ran out of memory: cannot create allocation of {size} bytes")
133 });
134 unsafe { alloc_bytes.ptr.copy_from(slice.as_ptr(), size) };
137 alloc_bytes
138 }
139
140 fn zeroed(size: Size, align: Align, params: MiriAllocParams) -> Option<Self> {
141 let size = size.bytes();
142 let align = align.bytes();
143 let alloc_fn = |layout, params: &MiriAllocParams| unsafe {
145 match params {
146 MiriAllocParams::Global => alloc::alloc_zeroed(layout),
147 #[cfg(target_os = "linux")]
148 MiriAllocParams::Isolated(alloc) => alloc.borrow_mut().alloc_zeroed(layout),
149 }
150 };
151 MiriAllocBytes::alloc_with(size, align, params, alloc_fn).ok()
152 }
153
154 fn as_mut_ptr(&mut self) -> *mut u8 {
155 self.ptr
156 }
157
158 fn as_ptr(&self) -> *const u8 {
159 self.ptr
160 }
161}