@@ -5,10 +5,9 @@ use std::path::{self, Path, PathBuf};
55use std:: str;
66
77use rustc_span:: Symbol ;
8- use rustc_target:: abi:: Size ;
8+ use rustc_target:: abi:: { Align , Size } ;
99use rustc_target:: spec:: abi:: Abi ;
1010
11- use crate :: shims:: alloc:: EvalContextExt as _;
1211use crate :: shims:: os_str:: bytes_to_os_str;
1312use crate :: shims:: windows:: * ;
1413use crate :: * ;
@@ -248,32 +247,63 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
248247 let size = this. read_target_usize ( size) ?;
249248 let heap_zero_memory = 0x00000008 ; // HEAP_ZERO_MEMORY
250249 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) ?;
253265 }
254266 "HeapFree" => {
255267 let [ handle, flags, ptr] =
256268 this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
257269 this. read_target_isize ( handle) ?;
258270 this. read_scalar ( flags) ?. to_u32 ( ) ?;
259271 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+ }
261277 this. write_scalar ( Scalar :: from_i32 ( 1 ) , dest) ?;
262278 }
263279 "HeapReAlloc" => {
264- let [ handle, flags, ptr , size] =
280+ let [ handle, flags, old_ptr , size] =
265281 this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
266282 this. read_target_isize ( handle) ?;
267283 this. read_scalar ( flags) ?. to_u32 ( ) ?;
268- let ptr = this. read_pointer ( ptr ) ?;
284+ let old_ptr = this. read_pointer ( old_ptr ) ?;
269285 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) ?;
272298 }
273299 "LocalFree" => {
274300 let [ ptr] = this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
275301 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+ }
277307 this. write_null ( dest) ?;
278308 }
279309
0 commit comments