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:
commit
9ef0de9815
5 changed files with 84 additions and 10 deletions
|
@ -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);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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)?;
|
||||
|
|
29
src/tools/miri/tests/pass/miri-alloc.rs
Normal file
29
src/tools/miri/tests/pass/miri-alloc.rs
Normal 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() {}
|
Loading…
Add table
Add a link
Reference in a new issue