Rollup merge of #139065 - RalfJung:miri-sync, r=RalfJung
Miri subtree update r? `@ghost`
This commit is contained in:
commit
b6699318fa
25 changed files with 234 additions and 95 deletions
30
Cargo.lock
30
Cargo.lock
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
f5729cfed3c45e061e8a443677fc1d5ef9277df7
|
||||
4ac032f857b46037b55c1fc0fa702450aad37f43
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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 { .. } =>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
)?;
|
||||
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
|
|
21
src/tools/miri/tests/fail/shims/input_arg_mismatch.rs
Normal file
21
src/tools/miri/tests/fail/shims/input_arg_mismatch.rs
Normal 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
|
||||
};
|
||||
}
|
17
src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr
Normal file
17
src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr
Normal 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
|
||||
|
21
src/tools/miri/tests/fail/shims/return_type_mismatch.rs
Normal file
21
src/tools/miri/tests/fail/shims/return_type_mismatch.rs
Normal 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
|
||||
};
|
||||
}
|
17
src/tools/miri/tests/fail/shims/return_type_mismatch.stderr
Normal file
17
src/tools/miri/tests/fail/shims/return_type_mismatch.stderr
Normal 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
|
||||
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue