@@ -5,10 +5,9 @@ use std::path::{self, Path, PathBuf};
5
5
use std:: str;
6
6
7
7
use rustc_span:: Symbol ;
8
- use rustc_target:: abi:: Size ;
8
+ use rustc_target:: abi:: { Align , Size } ;
9
9
use rustc_target:: spec:: abi:: Abi ;
10
10
11
- use crate :: shims:: alloc:: EvalContextExt as _;
12
11
use crate :: shims:: os_str:: bytes_to_os_str;
13
12
use crate :: shims:: windows:: * ;
14
13
use crate :: * ;
@@ -248,32 +247,63 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
248
247
let size = this. read_target_usize ( size) ?;
249
248
let heap_zero_memory = 0x00000008 ; // HEAP_ZERO_MEMORY
250
249
let zero_init = ( flags & heap_zero_memory) == heap_zero_memory;
251
- let res = this. malloc ( size, zero_init, MiriMemoryKind :: WinHeap ) ?;
252
- this. write_pointer ( res, dest) ?;
250
+ // Alignment is twice the pointer size.
251
+ // Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
252
+ let align = this. tcx . pointer_size ( ) . bytes ( ) . strict_mul ( 2 ) ;
253
+ let ptr = this. allocate_ptr (
254
+ Size :: from_bytes ( size) ,
255
+ Align :: from_bytes ( align) . unwrap ( ) ,
256
+ MiriMemoryKind :: WinHeap . into ( ) ,
257
+ ) ?;
258
+ if zero_init {
259
+ this. write_bytes_ptr (
260
+ ptr. into ( ) ,
261
+ iter:: repeat ( 0u8 ) . take ( usize:: try_from ( size) . unwrap ( ) ) ,
262
+ ) ?;
263
+ }
264
+ this. write_pointer ( ptr, dest) ?;
253
265
}
254
266
"HeapFree" => {
255
267
let [ handle, flags, ptr] =
256
268
this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
257
269
this. read_target_isize ( handle) ?;
258
270
this. read_scalar ( flags) ?. to_u32 ( ) ?;
259
271
let ptr = this. read_pointer ( ptr) ?;
260
- this. free ( ptr, MiriMemoryKind :: WinHeap ) ?;
272
+ // "This pointer can be NULL." It doesn't say what happens then, but presumably nothing.
273
+ // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree)
274
+ if !this. ptr_is_null ( ptr) ? {
275
+ this. deallocate_ptr ( ptr, None , MiriMemoryKind :: WinHeap . into ( ) ) ?;
276
+ }
261
277
this. write_scalar ( Scalar :: from_i32 ( 1 ) , dest) ?;
262
278
}
263
279
"HeapReAlloc" => {
264
- let [ handle, flags, ptr , size] =
280
+ let [ handle, flags, old_ptr , size] =
265
281
this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
266
282
this. read_target_isize ( handle) ?;
267
283
this. read_scalar ( flags) ?. to_u32 ( ) ?;
268
- let ptr = this. read_pointer ( ptr ) ?;
284
+ let old_ptr = this. read_pointer ( old_ptr ) ?;
269
285
let size = this. read_target_usize ( size) ?;
270
- let res = this. realloc ( ptr, size, MiriMemoryKind :: WinHeap ) ?;
271
- this. write_pointer ( res, dest) ?;
286
+ let align = this. tcx . pointer_size ( ) . bytes ( ) . strict_mul ( 2 ) ; // same as above
287
+ // The docs say that `old_ptr` must come from an earlier HeapAlloc or HeapReAlloc,
288
+ // so unlike C `realloc` we do *not* allow a NULL here.
289
+ // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heaprealloc)
290
+ let new_ptr = this. reallocate_ptr (
291
+ old_ptr,
292
+ None ,
293
+ Size :: from_bytes ( size) ,
294
+ Align :: from_bytes ( align) . unwrap ( ) ,
295
+ MiriMemoryKind :: WinHeap . into ( ) ,
296
+ ) ?;
297
+ this. write_pointer ( new_ptr, dest) ?;
272
298
}
273
299
"LocalFree" => {
274
300
let [ ptr] = this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
275
301
let ptr = this. read_pointer ( ptr) ?;
276
- this. free ( ptr, MiriMemoryKind :: WinLocal ) ?;
302
+ // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL."
303
+ // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree)
304
+ if !this. ptr_is_null ( ptr) ? {
305
+ this. deallocate_ptr ( ptr, None , MiriMemoryKind :: WinLocal . into ( ) ) ?;
306
+ }
277
307
this. write_null ( dest) ?;
278
308
}
279
309
0 commit comments