1
1
use std:: alloc:: Layout ;
2
2
use std:: borrow:: Cow ;
3
3
use std:: { alloc, slice} ;
4
+ #[ cfg( target_os = "linux" ) ]
5
+ use std:: { cell:: RefCell , rc:: Rc } ;
4
6
5
7
use rustc_abi:: { Align , Size } ;
6
8
use rustc_middle:: mir:: interpret:: AllocBytes ;
7
9
10
+ #[ cfg( target_os = "linux" ) ]
11
+ use crate :: alloc:: isolated_alloc:: IsolatedAlloc ;
8
12
use crate :: helpers:: ToU64 as _;
9
13
14
+ #[ derive( Clone , Debug ) ]
15
+ pub enum MiriAllocParams {
16
+ Global ,
17
+ #[ cfg( target_os = "linux" ) ]
18
+ Isolated ( Rc < RefCell < IsolatedAlloc > > ) ,
19
+ }
20
+
10
21
/// Allocation bytes that explicitly handle the layout of the data they're storing.
11
22
/// This is necessary to interface with native code that accesses the program store in Miri.
12
23
#[ derive( Debug ) ]
@@ -18,13 +29,16 @@ pub struct MiriAllocBytes {
18
29
/// * If `self.layout.size() == 0`, then `self.ptr` was allocated with the equivalent layout with size 1.
19
30
/// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
20
31
ptr : * mut u8 ,
32
+ /// Whether this instance of `MiriAllocBytes` had its allocation created by calling `alloc::alloc()`
33
+ /// (`Global`) or the discrete allocator (`Isolated`)
34
+ params : MiriAllocParams ,
21
35
}
22
36
23
37
impl Clone for MiriAllocBytes {
24
38
fn clone ( & self ) -> Self {
25
39
let bytes: Cow < ' _ , [ u8 ] > = Cow :: Borrowed ( self ) ;
26
40
let align = Align :: from_bytes ( self . layout . align ( ) . to_u64 ( ) ) . unwrap ( ) ;
27
- MiriAllocBytes :: from_bytes ( bytes, align, ( ) )
41
+ MiriAllocBytes :: from_bytes ( bytes, align, self . params . clone ( ) )
28
42
}
29
43
}
30
44
@@ -37,8 +51,16 @@ impl Drop for MiriAllocBytes {
37
51
} else {
38
52
self . layout
39
53
} ;
54
+
40
55
// SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
41
- unsafe { alloc:: dealloc ( self . ptr , alloc_layout) }
56
+ 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
+ }
42
64
}
43
65
}
44
66
@@ -67,35 +89,45 @@ impl MiriAllocBytes {
67
89
fn alloc_with (
68
90
size : u64 ,
69
91
align : u64 ,
70
- alloc_fn : impl FnOnce ( Layout ) -> * mut u8 ,
92
+ params : MiriAllocParams ,
93
+ alloc_fn : impl FnOnce ( Layout , & MiriAllocParams ) -> * mut u8 ,
71
94
) -> Result < MiriAllocBytes , ( ) > {
72
95
let size = usize:: try_from ( size) . map_err ( |_| ( ) ) ?;
73
96
let align = usize:: try_from ( align) . map_err ( |_| ( ) ) ?;
74
97
let layout = Layout :: from_size_align ( size, align) . map_err ( |_| ( ) ) ?;
75
98
// When size is 0 we allocate 1 byte anyway, to ensure each allocation has a unique address.
76
99
let alloc_layout =
77
100
if size == 0 { Layout :: from_size_align ( 1 , align) . unwrap ( ) } else { layout } ;
78
- let ptr = alloc_fn ( alloc_layout) ;
101
+ let ptr = alloc_fn ( alloc_layout, & params ) ;
79
102
if ptr. is_null ( ) {
80
103
Err ( ( ) )
81
104
} else {
82
105
// SAFETY: All `MiriAllocBytes` invariants are fulfilled.
83
- Ok ( Self { ptr, layout } )
106
+ Ok ( Self { ptr, layout, params } )
84
107
}
85
108
}
86
109
}
87
110
88
111
impl AllocBytes for MiriAllocBytes {
89
- /// Placeholder!
90
- type AllocParams = ( ) ;
112
+ type AllocParams = MiriAllocParams ;
91
113
92
- fn from_bytes < ' a > ( slice : impl Into < Cow < ' a , [ u8 ] > > , align : Align , _params : ( ) ) -> Self {
114
+ fn from_bytes < ' a > (
115
+ slice : impl Into < Cow < ' a , [ u8 ] > > ,
116
+ align : Align ,
117
+ params : MiriAllocParams ,
118
+ ) -> Self {
93
119
let slice = slice. into ( ) ;
94
120
let size = slice. len ( ) ;
95
121
let align = align. bytes ( ) ;
96
122
// SAFETY: `alloc_fn` will only be used with `size != 0`.
97
- let alloc_fn = |layout| unsafe { alloc:: alloc ( layout) } ;
98
- let alloc_bytes = MiriAllocBytes :: alloc_with ( size. to_u64 ( ) , align, alloc_fn)
123
+ 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)
99
131
. unwrap_or_else ( |( ) | {
100
132
panic ! ( "Miri ran out of memory: cannot create allocation of {size} bytes" )
101
133
} ) ;
@@ -105,12 +137,18 @@ impl AllocBytes for MiriAllocBytes {
105
137
alloc_bytes
106
138
}
107
139
108
- fn zeroed ( size : Size , align : Align , _params : ( ) ) -> Option < Self > {
140
+ fn zeroed ( size : Size , align : Align , params : MiriAllocParams ) -> Option < Self > {
109
141
let size = size. bytes ( ) ;
110
142
let align = align. bytes ( ) ;
111
143
// SAFETY: `alloc_fn` will only be used with `size != 0`.
112
- let alloc_fn = |layout| unsafe { alloc:: alloc_zeroed ( layout) } ;
113
- MiriAllocBytes :: alloc_with ( size, align, alloc_fn) . ok ( )
144
+ 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 ( )
114
152
}
115
153
116
154
fn as_mut_ptr ( & mut self ) -> * mut u8 {
0 commit comments