@@ -10,30 +10,48 @@ use crate::*;
10
10
11
11
impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
12
12
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
13
- /// Returns the minimum alignment for the target architecture.
14
- fn min_align ( & self ) -> Align {
13
+ /// Returns the minimum alignment for the target architecture for allocations of the given size .
14
+ fn min_align ( & self , size : u64 , kind : MiriMemoryKind ) -> Align {
15
15
let this = self . eval_context_ref ( ) ;
16
16
// List taken from `libstd/sys_common/alloc.rs`.
17
17
let min_align = match this. tcx . tcx . sess . target . target . arch . as_str ( ) {
18
18
"x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8 ,
19
19
"x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16 ,
20
20
arch => bug ! ( "Unsupported target architecture: {}" , arch) ,
21
21
} ;
22
- Align :: from_bytes ( min_align) . unwrap ( )
22
+ // Windows always aligns, even small allocations.
23
+ // Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
24
+ // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big.
25
+ if kind == MiriMemoryKind :: WinHeap || size >= min_align {
26
+ return Align :: from_bytes ( min_align) . unwrap ( ) ;
27
+ }
28
+ // We have `size < min_align`. Round `size` *down* to the next power of two and use that.
29
+ fn prev_power_of_two ( x : u64 ) -> u64 {
30
+ let next_pow2 = x. next_power_of_two ( ) ;
31
+ if next_pow2 == x {
32
+ // x *is* a power of two, just use that.
33
+ x
34
+ } else {
35
+ // x is between two powers, so next = 2*prev.
36
+ next_pow2 / 2
37
+ }
38
+ }
39
+ Align :: from_bytes ( prev_power_of_two ( size) ) . unwrap ( )
23
40
}
24
41
25
42
fn malloc (
26
43
& mut self ,
27
44
size : u64 ,
28
45
zero_init : bool ,
46
+ kind : MiriMemoryKind ,
29
47
) -> Scalar < Tag > {
30
48
let this = self . eval_context_mut ( ) ;
31
49
let tcx = & { this. tcx . tcx } ;
32
50
if size == 0 {
33
51
Scalar :: from_int ( 0 , this. pointer_size ( ) )
34
52
} else {
35
- let align = this. min_align ( ) ;
36
- let ptr = this. memory_mut ( ) . allocate ( Size :: from_bytes ( size) , align, MiriMemoryKind :: C . into ( ) ) ;
53
+ let align = this. min_align ( size , kind ) ;
54
+ let ptr = this. memory_mut ( ) . allocate ( Size :: from_bytes ( size) , align, kind . into ( ) ) ;
37
55
if zero_init {
38
56
// We just allocated this, the access cannot fail
39
57
this. memory_mut ( )
@@ -47,14 +65,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
47
65
fn free (
48
66
& mut self ,
49
67
ptr : Scalar < Tag > ,
68
+ kind : MiriMemoryKind ,
50
69
) -> InterpResult < ' tcx > {
51
70
let this = self . eval_context_mut ( ) ;
52
71
if !this. is_null ( ptr) ? {
53
72
let ptr = this. force_ptr ( ptr) ?;
54
73
this. memory_mut ( ) . deallocate (
55
74
ptr,
56
75
None ,
57
- MiriMemoryKind :: C . into ( ) ,
76
+ kind . into ( ) ,
58
77
) ?;
59
78
}
60
79
Ok ( ( ) )
@@ -64,39 +83,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
64
83
& mut self ,
65
84
old_ptr : Scalar < Tag > ,
66
85
new_size : u64 ,
86
+ kind : MiriMemoryKind ,
67
87
) -> InterpResult < ' tcx , Scalar < Tag > > {
68
88
let this = self . eval_context_mut ( ) ;
69
- let align = this. min_align ( ) ;
89
+ let new_align = this. min_align ( new_size , kind ) ;
70
90
if this. is_null ( old_ptr) ? {
71
91
if new_size == 0 {
72
92
Ok ( Scalar :: from_int ( 0 , this. pointer_size ( ) ) )
73
93
} else {
74
94
let new_ptr = this. memory_mut ( ) . allocate (
75
95
Size :: from_bytes ( new_size) ,
76
- align ,
77
- MiriMemoryKind :: C . into ( )
96
+ new_align ,
97
+ kind . into ( )
78
98
) ;
79
99
Ok ( Scalar :: Ptr ( new_ptr) )
80
100
}
81
101
} else {
82
102
let old_ptr = this. force_ptr ( old_ptr) ?;
83
103
let memory = this. memory_mut ( ) ;
84
- let old_size = Size :: from_bytes ( memory. get ( old_ptr. alloc_id ) ?. bytes . len ( ) as u64 ) ;
85
104
if new_size == 0 {
86
105
memory. deallocate (
87
106
old_ptr,
88
- Some ( ( old_size , align ) ) ,
89
- MiriMemoryKind :: C . into ( ) ,
107
+ None ,
108
+ kind . into ( ) ,
90
109
) ?;
91
110
Ok ( Scalar :: from_int ( 0 , this. pointer_size ( ) ) )
92
111
} else {
93
112
let new_ptr = memory. reallocate (
94
113
old_ptr,
95
- old_size,
96
- align,
114
+ None ,
97
115
Size :: from_bytes ( new_size) ,
98
- align ,
99
- MiriMemoryKind :: C . into ( ) ,
116
+ new_align ,
117
+ kind . into ( ) ,
100
118
) ?;
101
119
Ok ( Scalar :: Ptr ( new_ptr) )
102
120
}
@@ -145,14 +163,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
145
163
match link_name {
146
164
"malloc" => {
147
165
let size = this. read_scalar ( args[ 0 ] ) ?. to_usize ( this) ?;
148
- let res = this. malloc ( size, /*zero_init:*/ false ) ;
166
+ let res = this. malloc ( size, /*zero_init:*/ false , MiriMemoryKind :: C ) ;
149
167
this. write_scalar ( res, dest) ?;
150
168
}
151
169
"calloc" => {
152
170
let items = this. read_scalar ( args[ 0 ] ) ?. to_usize ( this) ?;
153
171
let len = this. read_scalar ( args[ 1 ] ) ?. to_usize ( this) ?;
154
172
let size = items. checked_mul ( len) . ok_or_else ( || InterpError :: Overflow ( mir:: BinOp :: Mul ) ) ?;
155
- let res = this. malloc ( size, /*zero_init:*/ true ) ;
173
+ let res = this. malloc ( size, /*zero_init:*/ true , MiriMemoryKind :: C ) ;
156
174
this. write_scalar ( res, dest) ?;
157
175
}
158
176
"posix_memalign" => {
@@ -187,12 +205,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
187
205
}
188
206
"free" => {
189
207
let ptr = this. read_scalar ( args[ 0 ] ) ?. not_undef ( ) ?;
190
- this. free ( ptr) ?;
208
+ this. free ( ptr, MiriMemoryKind :: C ) ?;
191
209
}
192
210
"realloc" => {
193
211
let old_ptr = this. read_scalar ( args[ 0 ] ) ?. not_undef ( ) ?;
194
212
let new_size = this. read_scalar ( args[ 1 ] ) ?. to_usize ( this) ?;
195
- let res = this. realloc ( old_ptr, new_size) ?;
213
+ let res = this. realloc ( old_ptr, new_size, MiriMemoryKind :: C ) ?;
196
214
this. write_scalar ( res, dest) ?;
197
215
}
198
216
@@ -262,12 +280,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
262
280
if !align. is_power_of_two ( ) {
263
281
return err ! ( HeapAllocNonPowerOfTwoAlignment ( align) ) ;
264
282
}
283
+ let align = Align :: from_bytes ( align) . unwrap ( ) ;
265
284
let new_ptr = this. memory_mut ( ) . reallocate (
266
285
ptr,
267
- Size :: from_bytes ( old_size) ,
268
- Align :: from_bytes ( align) . unwrap ( ) ,
286
+ Some ( ( Size :: from_bytes ( old_size) , align) ) ,
269
287
Size :: from_bytes ( new_size) ,
270
- Align :: from_bytes ( align) . unwrap ( ) ,
288
+ align,
271
289
MiriMemoryKind :: Rust . into ( ) ,
272
290
) ?;
273
291
this. write_scalar ( Scalar :: Ptr ( new_ptr) , dest) ?;
@@ -327,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
327
345
trace ! ( "__rust_maybe_catch_panic: {:?}" , f_instance) ;
328
346
329
347
// Now we make a function call.
330
- // TODO: consider making this reusable? `InterpretCx ::step` does something similar
348
+ // TODO: consider making this reusable? `InterpCx ::step` does something similar
331
349
// for the TLS destructors, and of course `eval_main`.
332
350
let mir = this. load_mir ( f_instance. def ) ?;
333
351
let ret_place = MPlaceTy :: dangling ( this. layout_of ( this. tcx . mk_unit ( ) ) ?, this) . into ( ) ;
@@ -765,22 +783,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
765
783
let flags = this. read_scalar ( args[ 1 ] ) ?. to_u32 ( ) ?;
766
784
let size = this. read_scalar ( args[ 2 ] ) ?. to_usize ( this) ?;
767
785
let zero_init = ( flags & 0x00000008 ) != 0 ; // HEAP_ZERO_MEMORY
768
- let res = this. malloc ( size, zero_init) ;
786
+ let res = this. malloc ( size, zero_init, MiriMemoryKind :: WinHeap ) ;
769
787
this. write_scalar ( res, dest) ?;
770
788
}
771
789
"HeapFree" => {
772
790
let _handle = this. read_scalar ( args[ 0 ] ) ?. to_isize ( this) ?;
773
791
let _flags = this. read_scalar ( args[ 1 ] ) ?. to_u32 ( ) ?;
774
792
let ptr = this. read_scalar ( args[ 2 ] ) ?. not_undef ( ) ?;
775
- this. free ( ptr) ?;
793
+ this. free ( ptr, MiriMemoryKind :: WinHeap ) ?;
776
794
this. write_scalar ( Scalar :: from_int ( 1 , Size :: from_bytes ( 4 ) ) , dest) ?;
777
795
}
778
796
"HeapReAlloc" => {
779
797
let _handle = this. read_scalar ( args[ 0 ] ) ?. to_isize ( this) ?;
780
798
let _flags = this. read_scalar ( args[ 1 ] ) ?. to_u32 ( ) ?;
781
799
let ptr = this. read_scalar ( args[ 2 ] ) ?. not_undef ( ) ?;
782
800
let size = this. read_scalar ( args[ 3 ] ) ?. to_usize ( this) ?;
783
- let res = this. realloc ( ptr, size) ?;
801
+ let res = this. realloc ( ptr, size, MiriMemoryKind :: WinHeap ) ?;
784
802
this. write_scalar ( res, dest) ?;
785
803
}
786
804
0 commit comments