Auto merge of #2606 - cbiffle:nostdio, r=RalfJung
Magic functions for writing to stdout/stderr. This enables I/O in no_std contexts (or, really, any Miri-specific OS-independent context). Combined with the `abort` intrinsic it should allow a reasonable test framework in no_std. **Question for maintainers:** So, the `no_std` panic test needs work, for two reasons: - First, its stdout includes Miri's whole message about the abort intrinsic having been used. I guess whatever panic handler you use in `std` contexts exits cleanly without triggering this message. Comparing the entire output with backtrace as golden seems fragile. - Second, likely for the same reason, the test framework appears to expect the test to exit successfully, when in fact it exits with status 1 due to the abort. This means the test doesn't actually pass right now. What shall I do there?
This commit is contained in:
commit
4dcf51b08f
@ -542,6 +542,16 @@ extern "Rust" {
|
||||
/// In particular, users should be aware that Miri will periodically attempt to garbage collect the
|
||||
/// contents of all stacks. Callers of this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
|
||||
fn miri_print_stacks(alloc_id: u64);
|
||||
|
||||
/// Miri-provided extern function to print (from the interpreter, not the
|
||||
/// program) the contents of a section of program memory, as bytes. Bytes
|
||||
/// written using this function will emerge from the interpreter's stdout.
|
||||
fn miri_write_to_stdout(bytes: &[u8]);
|
||||
|
||||
/// Miri-provided extern function to print (from the interpreter, not the
|
||||
/// 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]);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{collections::hash_map::Entry, iter};
|
||||
use std::{collections::hash_map::Entry, io::Write, iter};
|
||||
|
||||
use log::trace;
|
||||
|
||||
@ -462,6 +462,23 @@ fn emulate_foreign_item_by_name(
|
||||
this.handle_miri_resolve_frame_names(abi, link_name, args)?;
|
||||
}
|
||||
|
||||
// Writes some bytes to the interpreter's stdout/stderr. See the
|
||||
// README for details.
|
||||
"miri_write_to_stdout" | "miri_write_to_stderr" => {
|
||||
let [bytes] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||
let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair();
|
||||
let ptr = ptr.to_pointer(this)?;
|
||||
let len = len.to_machine_usize(this)?;
|
||||
let msg = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
|
||||
|
||||
// Note: we're ignoring errors writing to host stdout/stderr.
|
||||
let _ignore = match link_name.as_str() {
|
||||
"miri_write_to_stdout" => std::io::stdout().write_all(msg),
|
||||
"miri_write_to_stderr" => std::io::stderr().write_all(msg),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
// Standard C allocation
|
||||
"malloc" => {
|
||||
let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
|
41
src/tools/miri/tests/fail/panic/no_std.rs
Normal file
41
src/tools/miri/tests/fail/panic/no_std.rs
Normal file
@ -0,0 +1,41 @@
|
||||
#![feature(lang_items, start, core_intrinsics)]
|
||||
#![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
|
||||
|
||||
// Plumbing to let us use `writeln!` to host stderr:
|
||||
|
||||
extern "Rust" {
|
||||
fn miri_write_to_stderr(bytes: &[u8]);
|
||||
}
|
||||
|
||||
struct HostErr;
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
impl Write for HostErr {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
unsafe {
|
||||
miri_write_to_stderr(s.as_bytes());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Aaaand the test:
|
||||
|
||||
#[start]
|
||||
fn start(_: isize, _: *const *const u8) -> isize {
|
||||
panic!("blarg I am dead")
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
|
||||
writeln!(HostErr, "{panic_info}").ok();
|
||||
core::intrinsics::abort(); //~ ERROR: the program aborted execution
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() {}
|
19
src/tools/miri/tests/fail/panic/no_std.stderr
Normal file
19
src/tools/miri/tests/fail/panic/no_std.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
panicked at 'blarg I am dead', $DIR/no_std.rs:LL:CC
|
||||
error: abnormal termination: the program aborted execution
|
||||
--> $DIR/no_std.rs:LL:CC
|
||||
|
|
||||
LL | core::intrinsics::abort();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution
|
||||
|
|
||||
= note: inside `panic_handler` at $DIR/no_std.rs:LL:CC
|
||||
note: inside `start` at RUSTLIB/core/src/panic.rs:LL:CC
|
||||
--> $DIR/no_std.rs:LL:CC
|
||||
|
|
||||
LL | panic!("blarg I am dead")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -5,10 +5,30 @@
|
||||
// windows linker section, we can run this test on windows again.
|
||||
//@ignore-target-windows
|
||||
|
||||
// Plumbing to let us use `writeln!` to host stdout:
|
||||
|
||||
extern "Rust" {
|
||||
fn miri_write_to_stdout(bytes: &[u8]);
|
||||
}
|
||||
|
||||
struct Host;
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
impl Write for Host {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
unsafe {
|
||||
miri_write_to_stdout(s.as_bytes());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Aaaand the test:
|
||||
|
||||
#[start]
|
||||
fn start(_: isize, _: *const *const u8) -> isize {
|
||||
for _ in 0..10 {}
|
||||
|
||||
writeln!(Host, "hello, world!").unwrap();
|
||||
0
|
||||
}
|
||||
|
||||
|
1
src/tools/miri/tests/pass/no_std.stdout
Normal file
1
src/tools/miri/tests/pass/no_std.stdout
Normal file
@ -0,0 +1 @@
|
||||
hello, world!
|
Loading…
Reference in New Issue
Block a user