Skip to content

Commit 01b151e

Browse files
committed
separate windows heap functions from C heap shims
1 parent 7a0ee91 commit 01b151e

File tree

5 files changed

+56
-33
lines changed

5 files changed

+56
-33
lines changed

Diff for: src/tools/miri/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(let_chains)]
1313
#![feature(lint_reasons)]
1414
#![feature(trait_upcasting)]
15+
#![feature(strict_overflow_ops)]
1516
// Configure clippy and other lints
1617
#![allow(
1718
clippy::collapsible_else_if,

Diff for: src/tools/miri/src/shims/alloc.rs

+10-18
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ pub(super) fn check_alloc_request<'tcx>(size: u64, align: u64) -> InterpResult<'
1919

2020
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
2121
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
22-
/// Returns the minimum alignment for the target architecture for allocations of the given size.
23-
fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
22+
/// Returns the alignment that `malloc` would guarantee for requests of the given size.
23+
fn malloc_align(&self, size: u64) -> Align {
2424
let this = self.eval_context_ref();
2525
// The C standard says: "The pointer returned if the allocation succeeds is suitably aligned
2626
// so that it may be assigned to a pointer to any type of object with a fundamental
@@ -43,9 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4343
// - https://github.com/jemalloc/jemalloc/issues/1533
4444
// - https://github.com/llvm/llvm-project/issues/53540
4545
// - https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2293.htm
46-
// However, Windows `HeapAlloc` always aligns, even small allocations, so it gets different treatment here.
47-
// Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
48-
if kind == MiriMemoryKind::WinHeap || size >= max_fundamental_align {
46+
if size >= max_fundamental_align {
4947
return Align::from_bytes(max_fundamental_align).unwrap();
5048
}
5149
// C doesn't have zero-sized types, so presumably nothing is guaranteed here.
@@ -98,11 +96,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
9896
&mut self,
9997
size: u64,
10098
zero_init: bool,
101-
kind: MiriMemoryKind,
10299
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
103100
let this = self.eval_context_mut();
104-
let align = this.min_align(size, kind);
105-
let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
101+
let align = this.malloc_align(size);
102+
let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?;
106103
if zero_init {
107104
// We just allocated this, the access is definitely in-bounds and fits into our address space.
108105
this.write_bytes_ptr(
@@ -114,14 +111,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
114111
Ok(ptr.into())
115112
}
116113

117-
fn free(
118-
&mut self,
119-
ptr: Pointer<Option<Provenance>>,
120-
kind: MiriMemoryKind,
121-
) -> InterpResult<'tcx> {
114+
fn free(&mut self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx> {
122115
let this = self.eval_context_mut();
123116
if !this.ptr_is_null(ptr)? {
124-
this.deallocate_ptr(ptr, None, kind.into())?;
117+
this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?;
125118
}
126119
Ok(())
127120
}
@@ -130,13 +123,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
130123
&mut self,
131124
old_ptr: Pointer<Option<Provenance>>,
132125
new_size: u64,
133-
kind: MiriMemoryKind,
134126
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
135127
let this = self.eval_context_mut();
136-
let new_align = this.min_align(new_size, kind);
128+
let new_align = this.malloc_align(new_size);
137129
if this.ptr_is_null(old_ptr)? {
138130
// Here we must behave like `malloc`.
139-
self.malloc(new_size, /*zero_init*/ false, kind)
131+
self.malloc(new_size, /*zero_init*/ false)
140132
} else {
141133
if new_size == 0 {
142134
// C, in their infinite wisdom, made this UB.
@@ -148,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
148140
None,
149141
Size::from_bytes(new_size),
150142
new_align,
151-
kind.into(),
143+
MiriMemoryKind::C.into(),
152144
)?;
153145
Ok(new_ptr.into())
154146
}

Diff for: src/tools/miri/src/shims/foreign_items.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
421421
"malloc" => {
422422
let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
423423
let size = this.read_target_usize(size)?;
424-
let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?;
424+
let res = this.malloc(size, /*zero_init:*/ false)?;
425425
this.write_pointer(res, dest)?;
426426
}
427427
"calloc" => {
@@ -432,20 +432,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
432432
let size = items
433433
.checked_mul(len)
434434
.ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
435-
let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?;
435+
let res = this.malloc(size, /*zero_init:*/ true)?;
436436
this.write_pointer(res, dest)?;
437437
}
438438
"free" => {
439439
let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
440440
let ptr = this.read_pointer(ptr)?;
441-
this.free(ptr, MiriMemoryKind::C)?;
441+
this.free(ptr)?;
442442
}
443443
"realloc" => {
444444
let [old_ptr, new_size] =
445445
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
446446
let old_ptr = this.read_pointer(old_ptr)?;
447447
let new_size = this.read_target_usize(new_size)?;
448-
let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?;
448+
let res = this.realloc(old_ptr, new_size)?;
449449
this.write_pointer(res, dest)?;
450450
}
451451

Diff for: src/tools/miri/src/shims/unix/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
310310
this.write_null(dest)?;
311311
}
312312
Some(len) => {
313-
let res = this.realloc(ptr, len, MiriMemoryKind::C)?;
313+
let res = this.realloc(ptr, len)?;
314314
this.write_pointer(res, dest)?;
315315
}
316316
}

Diff for: src/tools/miri/src/shims/windows/foreign_items.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ use std::path::{self, Path, PathBuf};
55
use std::str;
66

77
use rustc_span::Symbol;
8-
use rustc_target::abi::Size;
8+
use rustc_target::abi::{Align, Size};
99
use rustc_target::spec::abi::Abi;
1010

11-
use crate::shims::alloc::EvalContextExt as _;
1211
use crate::shims::os_str::bytes_to_os_str;
1312
use crate::shims::windows::*;
1413
use 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

Comments
 (0)