Rollup merge of #139065 - RalfJung:miri-sync, r=RalfJung

Miri subtree update

r? `@ghost`
This commit is contained in:
Matthias Krüger 2025-03-28 21:18:30 +01:00 committed by GitHub
commit b6699318fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 234 additions and 95 deletions

View file

@ -535,7 +535,7 @@ dependencies = [
"termize",
"tokio",
"toml 0.7.8",
"ui_test 0.29.2",
"ui_test",
"walkdir",
]
@ -2262,7 +2262,7 @@ dependencies = [
"smallvec",
"tempfile",
"tikv-jemalloc-sys",
"ui_test 0.28.0",
"ui_test",
"windows-sys 0.52.0",
]
@ -5508,32 +5508,6 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]]
name = "ui_test"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576"
dependencies = [
"annotate-snippets 0.11.5",
"anyhow",
"bstr",
"cargo-platform",
"cargo_metadata 0.18.1",
"color-eyre",
"colored",
"comma",
"crossbeam-channel",
"indicatif",
"levenshtein",
"prettydiff",
"regex",
"rustc_version",
"rustfix",
"serde",
"serde_json",
"spanned",
]
[[package]]
name = "ui_test"
version = "0.29.2"

View file

@ -16,6 +16,7 @@ jobs:
- uses: actions/checkout@v4
- name: Build the sysroots
run: |
rustup toolchain install nightly
cargo install -f rustup-toolchain-install-master
./miri toolchain -c rust-docs # Docs are the only place targets are separated by tier
./miri install

View file

@ -1079,9 +1079,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "ui_test"
version = "0.28.0"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576"
checksum = "14bf63f2931a28a04af0bd24c5f850223d29f3a40afae49ed6ce442a65eb8652"
dependencies = [
"annotate-snippets",
"anyhow",

View file

@ -47,7 +47,7 @@ windows-sys = { version = "0.52", features = [
] }
[dev-dependencies]
ui_test = "0.28.0"
ui_test = "0.29.1"
colored = "2"
rustc_version = "0.4"
regex = "1.5.5"

View file

@ -237,8 +237,7 @@ inherent interpreter slowdown and a loss of parallelism.
You can get your test suite's parallelism back by running `cargo miri nextest run -jN`
(note that you will need [`cargo-nextest`](https://nexte.st) installed).
This works because `cargo-nextest` collects a list of all tests then launches a
separate `cargo miri run` for each test. You will need to specify a `-j` or `--test-threads`;
by default `cargo miri nextest run` runs one test at a time. For more details, see the
separate `cargo miri run` for each test. For more information about nextest, see the
[`cargo-nextest` Miri documentation](https://nexte.st/book/miri.html).
Note: This one-test-per-process model means that `cargo miri test` is able to detect data
@ -432,7 +431,8 @@ to Miri failing to detect cases of undefined behavior in a program.
* `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated
value from a load. This can help diagnose problems that disappear under
`-Zmiri-disable-weak-memory-emulation`.
* `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the [Tree Borrows] rules.
* <a name="-Zmiri-tree-borrows"><!-- The playground links here --></a>
`-Zmiri-tree-borrows` replaces [Stacked Borrows] with the [Tree Borrows] rules.
Tree Borrows is even more experimental than Stacked Borrows. While Tree Borrows
is still sound in the sense of catching all aliasing violations that current versions
of the compiler might exploit, it is likely that the eventual final aliasing model

View file

@ -10,7 +10,7 @@ fn main() {
}
fn read_i16(buffer: &[u8], index: usize) -> i16 {
const SIZE: usize = std::mem::size_of::<i16>();
const SIZE: usize = size_of::<i16>();
let mut bytes: [u8; SIZE] = [0u8; SIZE];
bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]);
unsafe { std::mem::transmute(bytes) }

View file

@ -467,7 +467,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
if let Some(i) = val.iter().position(|&s| s == "link") {
emit_link_hack = true;
val.remove(i);
if !val.iter().any(|&s| s == "metadata") {
if !val.contains(&"metadata") {
val.push("metadata");
}
}

View file

@ -166,7 +166,7 @@ case $HOST_TARGET in
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread epoll eventfd
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync concurrency thread epoll eventfd
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std

View file

@ -1 +1 @@
f5729cfed3c45e061e8a443677fc1d5ef9277df7
4ac032f857b46037b55c1fc0fa702450aad37f43

View file

@ -170,20 +170,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// This ensures the interpreted program and native code have the same view of memory.
let base_ptr = match info.kind {
AllocKind::LiveData => {
if this.tcx.try_get_global_alloc(alloc_id).is_some() {
if memory_kind == MiriMemoryKind::Global.into() {
// For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align)
.unwrap_or_else(|| {
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size)
});
let ptr = prepared_bytes.as_ptr();
// Store prepared allocation space to be picked up for use later.
// Store prepared allocation to be picked up for use later.
global_state
.prepared_alloc_bytes
.try_insert(alloc_id, prepared_bytes)
.unwrap();
ptr
} else {
// Non-global allocations are already in memory at this point so
// we can just get a pointer to where their data is stored.
this.get_alloc_bytes_unchecked_raw(alloc_id)?
}
}
@ -381,6 +383,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
align: Align,
) -> InterpResult<'tcx, MiriAllocBytes> {
let this = self.eval_context_ref();
assert!(this.tcx.try_get_global_alloc(id).is_some());
if this.machine.native_lib.is_some() {
// In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`.
// This additional call ensures that some `MiriAllocBytes` are always prepared, just in case

View file

@ -1150,7 +1150,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
loop {
if CTRL_C_RECEIVED.load(Relaxed) {
this.machine.handle_abnormal_termination();
std::process::exit(1);
throw_machine_stop!(TerminationInfo::Interrupted);
}
match this.machine.threads.schedule(&this.machine.clock)? {
SchedulingAction::ExecuteStep => {

View file

@ -16,6 +16,8 @@ pub enum TerminationInfo {
leak_check: bool,
},
Abort(String),
/// Miri was interrupted by a Ctrl+C from the user
Interrupted,
UnsupportedInIsolation(String),
StackedBorrowsUb {
msg: String,
@ -63,6 +65,7 @@ impl fmt::Display for TerminationInfo {
match self {
Exit { code, .. } => write!(f, "the evaluated program completed with exit code {code}"),
Abort(msg) => write!(f, "{msg}"),
Interrupted => write!(f, "interpretation was interrupted"),
UnsupportedInIsolation(msg) => write!(f, "{msg}"),
Int2PtrWithStrictProvenance =>
write!(
@ -226,6 +229,7 @@ pub fn report_error<'tcx>(
let title = match info {
&Exit { code, leak_check } => return Some((code, leak_check)),
Abort(_) => Some("abnormal termination"),
Interrupted => None,
UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance | UnsupportedForeignItem(_) =>
Some("unsupported operation"),
StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } =>

View file

@ -434,7 +434,6 @@ pub fn create_ecx<'tcx>(
/// Evaluates the entry function specified by `entry_id`.
/// Returns `Some(return_code)` if program execution completed.
/// Returns `None` if an evaluation error occurred.
#[expect(clippy::needless_lifetimes)]
pub fn eval_entry<'tcx>(
tcx: TyCtxt<'tcx>,
entry_id: DefId,

View file

@ -14,9 +14,10 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
use rustc_session::config::CrateType;
use rustc_span::{Span, Symbol};
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@ -994,10 +995,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
exp_abi: Conv,
link_name: Symbol,
args: &'a [OpTy<'tcx>],
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
where
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
{
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
if abi.c_variadic {
@ -1015,6 +1013,80 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)
}
/// Check that the given `caller_fn_abi` matches the expected ABI described by
/// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and the return the list of
/// arguments.
fn check_shim_abi<'a, const N: usize>(
&mut self,
link_name: Symbol,
caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
callee_abi: ExternAbi,
callee_input_tys: [Ty<'tcx>; N],
callee_output_ty: Ty<'tcx>,
caller_args: &'a [OpTy<'tcx>],
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
let this = self.eval_context_mut();
let mut inputs_and_output = callee_input_tys.to_vec();
inputs_and_output.push(callee_output_ty);
let fn_sig_binder = Binder::dummy(FnSig {
inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
c_variadic: false,
// This does not matter for the ABI.
safety: Safety::Safe,
abi: callee_abi,
});
let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?;
this.check_abi_and_shim_symbol_clash(caller_fn_abi, callee_fn_abi.conv, link_name)?;
if caller_fn_abi.c_variadic {
throw_ub_format!(
"ABI mismatch: calling a non-variadic function with a variadic caller-side signature"
);
}
if callee_fn_abi.fixed_count != caller_fn_abi.fixed_count {
throw_ub_format!(
"ABI mismatch: expected {} arguments, found {} arguments ",
callee_fn_abi.fixed_count,
caller_fn_abi.fixed_count
);
}
if callee_fn_abi.can_unwind && !caller_fn_abi.can_unwind {
throw_ub_format!(
"ABI mismatch: callee may unwind, but caller-side signature prohibits unwinding",
);
}
if !this.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
throw_ub!(AbiMismatchReturn {
caller_ty: caller_fn_abi.ret.layout.ty,
callee_ty: callee_fn_abi.ret.layout.ty
});
}
if let Some(index) = caller_fn_abi
.args
.iter()
.zip(callee_fn_abi.args.iter())
.map(|(caller_arg, callee_arg)| this.check_argument_compat(caller_arg, callee_arg))
.collect::<InterpResult<'tcx, Vec<bool>>>()?
.into_iter()
.position(|b| !b)
{
throw_ub!(AbiMismatchArgument {
caller_ty: caller_fn_abi.args[index].layout.ty,
callee_ty: callee_fn_abi.args[index].layout.ty
});
}
if let Ok(ops) = caller_args.try_into() {
return interp_ok(ops);
}
unreachable!()
}
/// Check shim for variadic function.
/// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
fn check_shim_variadic<'a, const N: usize>(
@ -1187,6 +1259,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
interp_ok(array)
}
fn mangle_internal_symbol<'a>(&'a mut self, name: &'static str) -> &'a str
where
'tcx: 'a,
{
let this = self.eval_context_mut();
let tcx = *this.tcx;
this.machine
.mangle_internal_symbol_cache
.entry(name)
.or_insert_with(|| mangle_internal_symbol(tcx, name))
}
}
impl<'tcx> MiriMachine<'tcx> {

View file

@ -611,6 +611,9 @@ pub struct MiriMachine<'tcx> {
pub(crate) reject_in_isolation_warned: RefCell<FxHashSet<String>>,
/// Remembers which int2ptr casts we have already warned about.
pub(crate) int2ptr_warned: RefCell<FxHashSet<Span>>,
/// Cache for `mangle_internal_symbol`.
pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>,
}
impl<'tcx> MiriMachine<'tcx> {
@ -757,6 +760,7 @@ impl<'tcx> MiriMachine<'tcx> {
native_call_mem_warned: Cell::new(false),
reject_in_isolation_warned: Default::default(),
int2ptr_warned: Default::default(),
mangle_internal_symbol_cache: Default::default(),
}
}
@ -930,6 +934,7 @@ impl VisitProvenance for MiriMachine<'_> {
native_call_mem_warned: _,
reject_in_isolation_warned: _,
int2ptr_warned: _,
mangle_internal_symbol_cache: _,
} = self;
threads.visit_provenance(visit);
@ -1540,7 +1545,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
fn before_terminator(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
ecx.machine.basic_block_count += 1u64; // a u64 that is only incremented by 1 will "never" overflow
ecx.machine.since_gc += 1;
// Possibly report our progress.
// Possibly report our progress. This will point at the terminator we are about to execute.
if let Some(report_progress) = ecx.machine.report_progress {
if ecx.machine.basic_block_count % u64::from(report_progress) == 0 {
ecx.emit_diagnostic(NonHaltingDiagnostic::ProgressReport {
@ -1559,6 +1564,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
}
// These are our preemption points.
// (This will only take effect after the terminator has been executed.)
ecx.maybe_preempt_active_thread();
// Make sure some time passes.

View file

@ -9,10 +9,9 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::CrateNum;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::AllocInit;
use rustc_middle::ty::Ty;
use rustc_middle::ty::{Instance, Ty};
use rustc_middle::{mir, ty};
use rustc_span::Symbol;
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::helpers::{ToHost, ToSoft};
@ -52,7 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Some shims forward to other MIR bodies.
match link_name.as_str() {
name if name == mangle_internal_symbol(*this.tcx, "__rust_alloc_error_handler") => {
name if name == this.mangle_internal_symbol("__rust_alloc_error_handler") => {
// Forward to the right symbol that implements this function.
let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
// in real code, this symbol does not exist without an allocator
@ -60,11 +59,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"`__rust_alloc_error_handler` cannot be called when no alloc error handler is set"
);
};
let name =
mangle_internal_symbol(*this.tcx, alloc_error_handler_name(handler_kind));
let handler = this
.lookup_exported_symbol(Symbol::intern(&name))?
.expect("missing alloc error handler symbol");
let name = Symbol::intern(
this.mangle_internal_symbol(alloc_error_handler_name(handler_kind)),
);
let handler =
this.lookup_exported_symbol(name)?.expect("missing alloc error handler symbol");
return interp_ok(Some(handler));
}
_ => {}
@ -138,30 +137,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Find it if it was not cached.
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None;
helpers::iter_exported_symbols(tcx, |cnum, def_id| {
let attrs = tcx.codegen_fn_attrs(def_id);
// Skip over imports of items.
if tcx.is_foreign_item(def_id) {
// Skip over imports of items
return interp_ok(());
}
// Skip over items without an explicitly defined symbol name.
if !(attrs.export_name.is_some()
|| attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|| attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL))
{
return interp_ok(());
}
let attrs = tcx.codegen_fn_attrs(def_id);
// FIXME use tcx.symbol_name(instance) instead
let symbol_name = if let Some(export_name) = attrs.export_name {
export_name
} else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|| attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
{
tcx.item_name(def_id)
} else {
// Skip over items without an explicitly defined symbol name.
return interp_ok(());
};
let symbol_name =
if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
Symbol::intern(&mangle_internal_symbol(tcx, symbol_name.as_str()))
} else {
symbol_name
};
if symbol_name == link_name {
let instance = Instance::mono(tcx, def_id);
let symbol_name = tcx.symbol_name(instance).name;
if symbol_name == link_name.as_str() {
if let Some((original_instance, original_cnum)) = instance_and_crate {
// Make sure we are consistent wrt what is 'first' and 'second'.
let original_span = tcx.def_span(original_instance.def_id()).data();
@ -505,9 +496,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// Rust allocation
name if name == mangle_internal_symbol(*this.tcx, "__rust_alloc")
|| name == "miri_alloc" =>
{
name if name == this.mangle_internal_symbol("__rust_alloc") || name == "miri_alloc" => {
let default = |ecx: &mut MiriInterpCx<'tcx>| {
// Only call `check_shim` when `#[global_allocator]` isn't used. When that
// macro is used, we act like no shim exists, so that the exported function can run.
@ -540,7 +529,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
_ => return this.emulate_allocator(default),
}
}
name if name == mangle_internal_symbol(*this.tcx, "__rust_alloc_zeroed") => {
name if name == this.mangle_internal_symbol("__rust_alloc_zeroed") => {
return this.emulate_allocator(|this| {
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
@ -559,7 +548,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_pointer(ptr, dest)
});
}
name if name == mangle_internal_symbol(*this.tcx, "__rust_dealloc")
name if name == this.mangle_internal_symbol("__rust_dealloc")
|| name == "miri_dealloc" =>
{
let default = |ecx: &mut MiriInterpCx<'tcx>| {
@ -592,7 +581,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
_ => return this.emulate_allocator(default),
}
}
name if name == mangle_internal_symbol(*this.tcx, "__rust_realloc") => {
name if name == this.mangle_internal_symbol("__rust_realloc") => {
return this.emulate_allocator(|this| {
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.

View file

@ -144,7 +144,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Directly return to caller of `try`.
StackPopCleanup::Goto {
ret: catch_unwind.ret,
unwind: mir::UnwindAction::Continue,
// `catch_fn` must not unwind.
unwind: mir::UnwindAction::Unreachable,
},
)?;

View file

@ -1,7 +1,7 @@
use std::ffi::OsStr;
use std::str;
use rustc_abi::Size;
use rustc_abi::{ExternAbi, Size};
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf;
use rustc_span::Symbol;
@ -200,7 +200,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write(fd, buf, count, Some(offset), dest)?;
}
"close" => {
let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
let [fd] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let result = this.close(fd)?;
this.write_scalar(result, dest)?;
}

View file

@ -0,0 +1,21 @@
//@ignore-target: windows # File handling is not implemented yet
//@compile-flags: -Zmiri-disable-isolation
use std::ffi::{CString, OsStr, c_char, c_int};
use std::os::unix::ffi::OsStrExt;
extern "C" {
fn open(path: *const c_char, oflag: c_int, ...) -> c_int;
// correct fd type is i32
fn close(fd: u32) -> c_int;
}
fn main() {
let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed");
let fd = unsafe {
open(c_path.as_ptr(), /* value does not matter */ 0)
} as u32;
let _ = unsafe {
close(fd);
//~^ ERROR: calling a function with argument of type i32 passing data of type u32
};
}

View file

@ -0,0 +1,17 @@
error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
--> tests/fail/shims/input_arg_mismatch.rs:LL:CC
|
LL | close(fd);
| ^^^^^^^^^ calling a function with argument of type i32 passing data of type u32
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: BACKTRACE:
= note: inside `main` at tests/fail/shims/input_arg_mismatch.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -0,0 +1,21 @@
//@ignore-target: windows # File handling is not implemented yet
//@compile-flags: -Zmiri-disable-isolation
use std::ffi::{CString, OsStr, c_char, c_int, c_short};
use std::os::unix::ffi::OsStrExt;
extern "C" {
fn open(path: *const c_char, oflag: c_int, ...) -> c_int;
// correct return type is i32
fn close(fd: c_int) -> c_short;
}
fn main() {
let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed");
let fd = unsafe {
open(c_path.as_ptr(), /* value does not matter */ 0)
};
let _ = unsafe {
close(fd);
//~^ ERROR: calling a function with return type i32 passing return place of type i16
};
}

View file

@ -0,0 +1,17 @@
error: Undefined Behavior: calling a function with return type i32 passing return place of type i16
--> tests/fail/shims/return_type_mismatch.rs:LL:CC
|
LL | close(fd);
| ^^^^^^^^^ calling a function with return type i32 passing return place of type i16
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: BACKTRACE:
= note: inside `main` at tests/fail/shims/return_type_mismatch.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -64,7 +64,7 @@ fn wait_wrong_val() {
),
-1,
);
assert_eq!(*libc::__errno_location(), libc::EAGAIN);
assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EAGAIN);
}
}
@ -85,7 +85,7 @@ fn wait_timeout() {
),
-1,
);
assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
}
assert!((200..1000).contains(&start.elapsed().as_millis()));
@ -124,7 +124,7 @@ fn wait_absolute_timeout() {
),
-1,
);
assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
}
assert!((200..1000).contains(&start.elapsed().as_millis()));

View file

@ -56,8 +56,7 @@ fn test_pipe_threaded() {
assert_eq!(res, 5);
assert_eq!(buf, "abcde".as_bytes());
});
// FIXME: we should yield here once blocking is implemented.
//thread::yield_now();
thread::yield_now();
let data = "abcde".as_bytes().as_ptr();
let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
@ -65,14 +64,11 @@ fn test_pipe_threaded() {
// Read and write from different direction
let thread2 = thread::spawn(move || {
// FIXME: we should yield here once blocking is implemented.
//thread::yield_now();
thread::yield_now();
let data = "12345".as_bytes().as_ptr();
let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
assert_eq!(res, 5);
});
// FIXME: we should not yield here once blocking is implemented.
thread::yield_now();
let mut buf: [u8; 5] = [0; 5];
let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
assert_eq!(res, 5);

View file

@ -1281,7 +1281,6 @@ fn test_non_determinism() {
/// Ensure that the operation is non-deterministic
#[track_caller]
fn ensure_nondet<T: PartialEq + std::fmt::Debug>(f: impl Fn() -> T) {
let rounds = 16;
let first = f();
for _ in 1..rounds {