1
Fork 0

Auto merge of #2657 - mkroening:miri-alloc, r=RalfJung

Add miri_alloc, miri_dealloc

`miri_alloc` and `miri_dealloc` are basically the same as `__rust_alloc` and `__rust_dealloc` respectively, but without the check for a global allocator.

This should allow bootstrapping an allocator in environments, where no fundamental way of allocating memory is available (`no_std` + `alloc` in Miri).
This commit is contained in:
bors 2022-11-13 12:24:18 +00:00
commit 9ef0de9815
5 changed files with 84 additions and 10 deletions

View file

@ -568,6 +568,15 @@ extern "Rust" {
/// program) the contents of a section of program memory, as bytes. Bytes
/// written using this function will emerge from the interpreter's stderr.
fn miri_write_to_stderr(bytes: &[u8]);
/// Miri-provided extern function to allocate memory from the interpreter.
///
/// This is useful when no fundamental way of allocating memory is
/// available, e.g. when using `no_std` + `alloc`.
fn miri_alloc(size: usize, align: usize) -> *mut u8;
/// Miri-provided extern function to deallocate memory.
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
}
```

View file

@ -686,7 +686,10 @@ impl VClockAlloc {
let (alloc_timestamp, alloc_index) = match kind {
// User allocated and stack memory should track allocation.
MemoryKind::Machine(
MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap,
MiriMemoryKind::Rust
| MiriMemoryKind::Miri
| MiriMemoryKind::C
| MiriMemoryKind::WinHeap,
)
| MemoryKind::Stack => {
let (alloc_index, clocks) = global.current_thread_state(thread_mgr);

View file

@ -77,6 +77,8 @@ impl VisitTags for FrameData<'_> {
pub enum MiriMemoryKind {
/// `__rust_alloc` memory.
Rust,
/// `miri_alloc` memory.
Miri,
/// `malloc` memory.
C,
/// Windows `HeapAlloc` memory.
@ -110,7 +112,7 @@ impl MayLeak for MiriMemoryKind {
fn may_leak(self) -> bool {
use self::MiriMemoryKind::*;
match self {
Rust | C | WinHeap | Runtime => false,
Rust | Miri | C | WinHeap | Runtime => false,
Machine | Global | ExternStatic | Tls => true,
}
}
@ -121,6 +123,7 @@ impl fmt::Display for MiriMemoryKind {
use self::MiriMemoryKind::*;
match self {
Rust => write!(f, "Rust heap"),
Miri => write!(f, "Miri bare-metal heap"),
C => write!(f, "C heap"),
WinHeap => write!(f, "Windows heap"),
Machine => write!(f, "machine-managed memory"),

View file

@ -513,22 +513,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
// Rust allocation
"__rust_alloc" => {
"__rust_alloc" | "miri_alloc" => {
let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let size = this.read_scalar(size)?.to_machine_usize(this)?;
let align = this.read_scalar(align)?.to_machine_usize(this)?;
return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| {
let default = |this: &mut MiriInterpCx<'mir, 'tcx>| {
Self::check_alloc_request(size, align)?;
let memory_kind = match link_name.as_str() {
"__rust_alloc" => MiriMemoryKind::Rust,
"miri_alloc" => MiriMemoryKind::Miri,
_ => unreachable!(),
};
let ptr = this.allocate_ptr(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::Rust.into(),
memory_kind.into(),
)?;
this.write_pointer(ptr, dest)
});
};
match link_name.as_str() {
"__rust_alloc" => return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
"miri_alloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
},
_ => unreachable!(),
}
}
"__rust_alloc_zeroed" => {
let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
@ -549,20 +564,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_pointer(ptr, dest)
});
}
"__rust_dealloc" => {
"__rust_dealloc" | "miri_dealloc" => {
let [ptr, old_size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
let align = this.read_scalar(align)?.to_machine_usize(this)?;
return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| {
let default = |this: &mut MiriInterpCx<'mir, 'tcx>| {
let memory_kind = match link_name.as_str() {
"__rust_dealloc" => MiriMemoryKind::Rust,
"miri_dealloc" => MiriMemoryKind::Miri,
_ => unreachable!(),
};
// No need to check old_size/align; we anyway check that they match the allocation.
this.deallocate_ptr(
ptr,
Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
MiriMemoryKind::Rust.into(),
memory_kind.into(),
)
});
};
match link_name.as_str() {
"__rust_dealloc" => return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
"miri_dealloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
}
_ => unreachable!(),
}
}
"__rust_realloc" => {
let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?;

View file

@ -0,0 +1,29 @@
#![feature(lang_items, start)]
#![no_std]
// windows tls dtors go through libstd right now, thus this test
// cannot pass. When windows tls dtors go through the special magic
// windows linker section, we can run this test on windows again.
//@ignore-target-windows: no-std not supported on Windows
extern "Rust" {
fn miri_alloc(size: usize, align: usize) -> *mut u8;
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
}
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
unsafe {
let ptr = miri_alloc(123, 1);
core::ptr::write_bytes(ptr, 0u8, 123);
miri_dealloc(ptr, 123, 1);
}
0
}
#[panic_handler]
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
loop {}
}
#[lang = "eh_personality"]
fn eh_personality() {}