diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 1c6a2daa093d..32494141589a 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -624,6 +624,7 @@ Definite bugs found:
* [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
* [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
* [Rare Deadlock in the thread (un)parking example code](https://github.com/rust-lang/rust/issues/145816)
+* [`winit` registering a global constructor with the wrong ABI on Windows](https://github.com/rust-windowing/winit/issues/4435)
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index c7ae335d0479..5016e3b66ca6 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -14,7 +14,7 @@
use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::Mutability;
use rustc_middle::ty::layout::TyAndLayout;
-use rustc_span::Span;
+use rustc_span::{DUMMY_SP, Span};
use rustc_target::spec::Os;
use crate::concurrency::GlobalDataRaceHandler;
@@ -174,6 +174,10 @@ pub struct Thread<'tcx> {
/// The virtual call stack.
stack: Vec>>,
+ /// A span that explains where the thread (or more specifically, its current root
+ /// frame) "comes from".
+ pub(crate) origin_span: Span,
+
/// The function to call when the stack ran empty, to figure out what to do next.
/// Conceptually, this is the interpreter implementation of the things that happen 'after' the
/// Rust language entry point for this thread returns (usually implemented by the C or OS runtime).
@@ -303,6 +307,7 @@ fn new(name: Option<&str>, on_stack_empty: Option>) ->
state: ThreadState::Enabled,
thread_name: name.map(|name| Vec::from(name.as_bytes())),
stack: Vec::new(),
+ origin_span: DUMMY_SP,
top_user_relevant_frame: None,
join_status: ThreadJoinStatus::Joinable,
unwind_payloads: Vec::new(),
@@ -318,6 +323,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
unwind_payloads: panic_payload,
last_error,
stack,
+ origin_span: _,
top_user_relevant_frame: _,
state: _,
thread_name: _,
@@ -584,6 +590,10 @@ pub fn active_thread_ref(&self) -> &Thread<'tcx> {
&self.threads[self.active_thread]
}
+ pub fn thread_ref(&self, thread_id: ThreadId) -> &Thread<'tcx> {
+ &self.threads[thread_id]
+ }
+
/// Mark the thread as detached, which means that no other thread will try
/// to join it and the thread is responsible for cleaning up.
///
@@ -704,8 +714,9 @@ fn run_timeout_callback(&mut self) -> InterpResult<'tcx> {
#[inline]
fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> {
let this = self.eval_context_mut();
- let mut callback = this
- .active_thread_mut()
+ let active_thread = this.active_thread_mut();
+ active_thread.origin_span = DUMMY_SP; // reset, the old value no longer applied
+ let mut callback = active_thread
.on_stack_empty
.take()
.expect("`on_stack_empty` not set up, or already running");
@@ -891,11 +902,11 @@ fn start_regular_thread(
let this = self.eval_context_mut();
// Create the new thread
+ let current_span = this.machine.current_user_relevant_span();
let new_thread_id = this.machine.threads.create_thread({
let mut state = tls::TlsDtorsState::default();
Box::new(move |m| state.on_stack_empty(m))
});
- let current_span = this.machine.current_user_relevant_span();
match &mut this.machine.data_race {
GlobalDataRaceHandler::None => {}
GlobalDataRaceHandler::Vclocks(data_race) =>
@@ -934,12 +945,12 @@ fn start_regular_thread(
// it.
let ret_place = this.allocate(ret_layout, MiriMemoryKind::Machine.into())?;
- this.call_function(
+ this.call_thread_root_function(
instance,
start_abi,
&[func_arg],
Some(&ret_place),
- ReturnContinuation::Stop { cleanup: true },
+ current_span,
)?;
// Restore the old active thread frame.
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 8e252d306b29..01f77f261d70 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -444,7 +444,11 @@ pub fn report_result<'tcx>(
write!(primary_msg, "{}", format_interp_error(ecx.tcx.dcx(), res)).unwrap();
if labels.is_empty() {
- labels.push(format!("{} occurred here", title.unwrap_or("error")));
+ labels.push(format!(
+ "{} occurred {}",
+ title.unwrap_or("error"),
+ if stacktrace.is_empty() { "due to this code" } else { "here" }
+ ));
}
report_msg(
@@ -552,7 +556,14 @@ pub fn report_msg<'tcx>(
thread: Option,
machine: &MiriMachine<'tcx>,
) {
- let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
+ let span = match stacktrace.first() {
+ Some(fi) => fi.span,
+ None =>
+ match thread {
+ Some(thread_id) => machine.threads.thread_ref(thread_id).origin_span,
+ None => DUMMY_SP,
+ },
+ };
let sess = machine.tcx.sess;
let level = match diag_level {
DiagLevel::Error => Level::Error,
@@ -620,6 +631,12 @@ pub fn report_msg<'tcx>(
err.note(format!("{frame_info} at {span}"));
}
}
+ } else if stacktrace.len() == 0 && !span.is_dummy() {
+ err.note(format!(
+ "this {} occurred while pushing a call frame onto an empty stack",
+ level.to_str()
+ ));
+ err.note("the span indicates which code caused the function to be called, but may not be the literal call site");
}
err.emit();
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 383a4e2ea4b0..75b7e9f5966f 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -472,6 +472,22 @@ fn call_function(
)
}
+ /// Call a function in an "empty" thread.
+ fn call_thread_root_function(
+ &mut self,
+ f: ty::Instance<'tcx>,
+ caller_abi: ExternAbi,
+ args: &[ImmTy<'tcx>],
+ dest: Option<&MPlaceTy<'tcx>>,
+ span: Span,
+ ) -> InterpResult<'tcx> {
+ let this = self.eval_context_mut();
+ assert!(this.active_thread_stack().is_empty());
+ assert!(this.active_thread_ref().origin_span.is_dummy());
+ this.active_thread_mut().origin_span = span;
+ this.call_function(f, caller_abi, args, dest, ReturnContinuation::Stop { cleanup: true })
+ }
+
/// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter
/// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`.
/// The range is relative to `place`.
@@ -995,11 +1011,12 @@ fn expect_target_feature_for_intrinsic(
interp_ok(())
}
- /// Lookup an array of immediates from any linker sections matching the provided predicate.
+ /// Lookup an array of immediates from any linker sections matching the provided predicate,
+ /// with the spans of where they were found.
fn lookup_link_section(
&mut self,
include_name: impl Fn(&str) -> bool,
- ) -> InterpResult<'tcx, Vec>> {
+ ) -> InterpResult<'tcx, Vec<(ImmTy<'tcx>, Span)>> {
let this = self.eval_context_mut();
let tcx = this.tcx.tcx;
@@ -1012,6 +1029,7 @@ fn lookup_link_section(
};
if include_name(link_section.as_str()) {
let instance = ty::Instance::mono(tcx, def_id);
+ let span = tcx.def_span(def_id);
let const_val = this.eval_global(instance).unwrap_or_else(|err| {
panic!(
"failed to evaluate static in required link_section: {def_id:?}\n{err:?}"
@@ -1019,12 +1037,12 @@ fn lookup_link_section(
});
match const_val.layout.ty.kind() {
ty::FnPtr(..) => {
- array.push(this.read_immediate(&const_val)?);
+ array.push((this.read_immediate(&const_val)?, span));
}
ty::Array(elem_ty, _) if matches!(elem_ty.kind(), ty::FnPtr(..)) => {
let mut elems = this.project_array_fields(&const_val)?;
while let Some((_idx, elem)) = elems.next(this)? {
- array.push(this.read_immediate(&elem)?);
+ array.push((this.read_immediate(&elem)?, span));
}
}
_ =>
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index b30395b738b1..fe501b8d7b30 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -39,6 +39,7 @@
clippy::needless_question_mark,
clippy::needless_lifetimes,
clippy::too_long_first_doc_paragraph,
+ clippy::len_zero,
// We don't use translatable diagnostics
rustc::diagnostic_outside_of_impl,
// We are not implementing queries here so it's fine
diff --git a/src/tools/miri/src/shims/global_ctor.rs b/src/tools/miri/src/shims/global_ctor.rs
index c56251bbe63a..d3296e4445f7 100644
--- a/src/tools/miri/src/shims/global_ctor.rs
+++ b/src/tools/miri/src/shims/global_ctor.rs
@@ -3,6 +3,7 @@
use std::task::Poll;
use rustc_abi::ExternAbi;
+use rustc_span::Span;
use rustc_target::spec::BinaryFormat;
use crate::*;
@@ -15,7 +16,7 @@ enum GlobalCtorStatePriv<'tcx> {
#[default]
Init,
/// The list of constructor functions that we still have to call.
- Ctors(Vec>),
+ Ctors(Vec<(ImmTy<'tcx>, Span)>),
Done,
}
@@ -67,19 +68,19 @@ pub fn on_stack_empty(
break 'new_state Ctors(ctors);
}
Ctors(ctors) => {
- if let Some(ctor) = ctors.pop() {
+ if let Some((ctor, span)) = ctors.pop() {
let this = this.eval_context_mut();
let ctor = ctor.to_scalar().to_pointer(this)?;
let thread_callback = this.get_ptr_fn(ctor)?.as_instance()?;
// The signature of this function is `unsafe extern "C" fn()`.
- this.call_function(
+ this.call_thread_root_function(
thread_callback,
ExternAbi::C { unwind: false },
&[],
None,
- ReturnContinuation::Stop { cleanup: true },
+ span,
)?;
return interp_ok(Poll::Pending); // we stay in this state (but `ctors` got shorter)
diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs
index 2159c41ab16c..3ecd9b1ead38 100644
--- a/src/tools/miri/src/shims/tls.rs
+++ b/src/tools/miri/src/shims/tls.rs
@@ -6,6 +6,7 @@
use rustc_abi::{ExternAbi, HasDataLayout, Size};
use rustc_middle::ty;
+use rustc_span::Span;
use rustc_target::spec::Os;
use crate::*;
@@ -17,7 +18,7 @@ pub struct TlsEntry<'tcx> {
/// The data for this key. None is used to represent NULL.
/// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.)
data: BTreeMap,
- dtor: Option>,
+ dtor: Option<(ty::Instance<'tcx>, Span)>,
}
#[derive(Default, Debug)]
@@ -38,7 +39,7 @@ pub struct TlsData<'tcx> {
/// On macOS, each thread holds a list of destructor functions with their
/// respective data arguments.
- macos_thread_dtors: BTreeMap, Scalar)>>,
+ macos_thread_dtors: BTreeMap, Scalar, Span)>>,
}
impl<'tcx> Default for TlsData<'tcx> {
@@ -57,7 +58,7 @@ impl<'tcx> TlsData<'tcx> {
#[expect(clippy::arithmetic_side_effects)]
pub fn create_tls_key(
&mut self,
- dtor: Option>,
+ dtor: Option<(ty::Instance<'tcx>, Span)>,
max_size: Size,
) -> InterpResult<'tcx, TlsKey> {
let new_key = self.next_key;
@@ -126,8 +127,9 @@ pub fn add_macos_thread_dtor(
thread: ThreadId,
dtor: ty::Instance<'tcx>,
data: Scalar,
+ span: Span,
) -> InterpResult<'tcx> {
- self.macos_thread_dtors.entry(thread).or_default().push((dtor, data));
+ self.macos_thread_dtors.entry(thread).or_default().push((dtor, data, span));
interp_ok(())
}
@@ -154,7 +156,7 @@ fn fetch_tls_dtor(
&mut self,
key: Option,
thread_id: ThreadId,
- ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> {
+ ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey, Span)> {
use std::ops::Bound::*;
let thread_local = &mut self.keys;
@@ -172,11 +174,10 @@ fn fetch_tls_dtor(
for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) {
match data.entry(thread_id) {
BTreeEntry::Occupied(entry) => {
- if let Some(dtor) = dtor {
+ if let Some((dtor, span)) = dtor {
// Set TLS data to NULL, and call dtor with old value.
let data_scalar = entry.remove();
- let ret = Some((*dtor, data_scalar, key));
- return ret;
+ return Some((*dtor, data_scalar, key, *span));
}
}
BTreeEntry::Vacant(_) => {}
@@ -205,7 +206,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
for scalar in keys.values().flat_map(|v| v.data.values()) {
scalar.visit_provenance(visit);
}
- for (_, scalar) in macos_thread_dtors.values().flatten() {
+ for (_, scalar, _) in macos_thread_dtors.values().flatten() {
scalar.visit_provenance(visit);
}
}
@@ -222,7 +223,7 @@ enum TlsDtorsStatePriv<'tcx> {
PthreadDtors(RunningDtorState),
/// For Windows Dtors, we store the list of functions that we still have to call.
/// These are functions from the magic `.CRT$XLB` linker section.
- WindowsDtors(Vec>),
+ WindowsDtors(Vec<(ImmTy<'tcx>, Span)>),
Done,
}
@@ -273,8 +274,8 @@ pub fn on_stack_empty(
}
}
WindowsDtors(dtors) => {
- if let Some(dtor) = dtors.pop() {
- this.schedule_windows_tls_dtor(dtor)?;
+ if let Some((dtor, span)) = dtors.pop() {
+ this.schedule_windows_tls_dtor(dtor, span)?;
return interp_ok(Poll::Pending); // we stay in this state (but `dtors` got shorter)
} else {
// No more destructors to run.
@@ -297,7 +298,7 @@ impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {}
trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
/// Schedule TLS destructors for Windows.
/// On windows, TLS destructors are managed by std.
- fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec>> {
+ fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec<(ImmTy<'tcx>, Span)>> {
let this = self.eval_context_mut();
// Windows has a special magic linker section that is run on certain events.
@@ -305,7 +306,7 @@ fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec>> {
interp_ok(this.lookup_link_section(|section| section == ".CRT$XLB")?)
}
- fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> {
+ fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>, span: Span) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let dtor = dtor.to_scalar().to_pointer(this)?;
@@ -320,12 +321,12 @@ fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx>
// The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
// FIXME: `h` should be a handle to the current module and what `pv` should be is unknown
// but both are ignored by std.
- this.call_function(
+ this.call_thread_root_function(
thread_callback,
ExternAbi::System { unwind: false },
&[null_ptr.clone(), ImmTy::from_scalar(reason, this.machine.layouts.u32), null_ptr],
None,
- ReturnContinuation::Stop { cleanup: true },
+ span,
)?;
interp_ok(())
}
@@ -338,15 +339,15 @@ fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, Poll<()>> {
// registers another destructor, it will be run next.
// See https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/DyldRuntimeState.cpp#L2277
let dtor = this.machine.tls.macos_thread_dtors.get_mut(&thread_id).and_then(Vec::pop);
- if let Some((instance, data)) = dtor {
+ if let Some((instance, data, span)) = dtor {
trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id);
- this.call_function(
+ this.call_thread_root_function(
instance,
ExternAbi::C { unwind: false },
&[ImmTy::from_scalar(data, this.machine.layouts.mut_raw_ptr)],
None,
- ReturnContinuation::Stop { cleanup: true },
+ span,
)?;
return interp_ok(Poll::Pending);
@@ -370,7 +371,7 @@ fn schedule_next_pthread_tls_dtor(
// We ran each dtor once, start over from the beginning.
None => this.machine.tls.fetch_tls_dtor(None, active_thread),
};
- if let Some((instance, ptr, key)) = dtor {
+ if let Some((instance, ptr, key, span)) = dtor {
state.last_key = Some(key);
trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread);
assert!(
@@ -378,12 +379,12 @@ fn schedule_next_pthread_tls_dtor(
"data can't be NULL when dtor is called!"
);
- this.call_function(
+ this.call_thread_root_function(
instance,
ExternAbi::C { unwind: false },
&[ImmTy::from_scalar(ptr, this.machine.layouts.mut_raw_ptr)],
None,
- ReturnContinuation::Stop { cleanup: true },
+ span,
)?;
return interp_ok(Poll::Pending);
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 378a8537fc73..64b8376ff4aa 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -634,7 +634,10 @@ fn emulate_foreign_item_inner(
// Extract the function type out of the signature (that seems easier than constructing it ourselves).
let dtor = if !this.ptr_is_null(dtor)? {
- Some(this.get_ptr_fn(dtor)?.as_instance()?)
+ Some((
+ this.get_ptr_fn(dtor)?.as_instance()?,
+ this.machine.current_user_relevant_span(),
+ ))
} else {
None
};
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index ed22457ec01a..dd7b95bdc82b 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -158,7 +158,12 @@ fn emulate_foreign_item_inner(
let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
let data = this.read_scalar(data)?;
let active_thread = this.active_thread();
- this.machine.tls.add_macos_thread_dtor(active_thread, dtor, data)?;
+ this.machine.tls.add_macos_thread_dtor(
+ active_thread,
+ dtor,
+ data,
+ this.machine.current_user_relevant_span(),
+ )?;
}
// Querying system information
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
index 520bc9572f86..6fec6500cc96 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
@@ -1,5 +1,4 @@
//@ignore-target: windows # No pthreads on Windows
-//~^ERROR: calling a function with more arguments than it expected
//! The thread function must have exactly one argument.
@@ -17,6 +16,7 @@ fn main() {
mem::transmute(thread_start);
assert_eq!(
libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
+ //~^ERROR: calling a function with more arguments than it expected
0
);
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
index 4d5a80c828cd..fef91e85470d 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
@@ -1,9 +1,13 @@
error: Undefined Behavior: calling a function with more arguments than it expected
+ --> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC
+ |
+LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
|
- = note: Undefined Behavior occurred here
- = note: (no span available)
= 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
+ = note: this error occurred while pushing a call frame onto an empty stack
+ = note: the span indicates which code caused the function to be called, but may not be the literal call site
error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
index 92d8a765e511..cb55b0f92ee6 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
@@ -1,5 +1,4 @@
//@ignore-target: windows # No pthreads on Windows
-//~^ERROR: calling a function with fewer arguments than it requires
//! The thread function must have exactly one argument.
@@ -17,6 +16,7 @@ fn main() {
mem::transmute(thread_start);
assert_eq!(
libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
+ //~^ERROR: calling a function with fewer arguments than it requires
0
);
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
index 1bc79411197c..4d70576d784c 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
@@ -1,9 +1,13 @@
error: Undefined Behavior: calling a function with fewer arguments than it requires
+ --> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC
+ |
+LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
|
- = note: Undefined Behavior occurred here
- = note: (no span available)
= 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
+ = note: this error occurred while pushing a call frame onto an empty stack
+ = note: the span indicates which code caused the function to be called, but may not be the literal call site
error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs
new file mode 100644
index 000000000000..b5eec2db201c
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs
@@ -0,0 +1,21 @@
+//@ignore-target: windows # No pthreads on Windows
+
+use std::{mem, ptr};
+
+pub type Key = libc::pthread_key_t;
+
+pub unsafe fn create(dtor: unsafe fn(*mut u8)) -> Key {
+ let mut key = 0;
+ assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
+ //~^ERROR: calling a function with calling convention "Rust"
+ key
+}
+
+unsafe fn dtor(_ptr: *mut u8) {}
+
+fn main() {
+ unsafe {
+ let key = create(dtor);
+ libc::pthread_setspecific(key, ptr::without_provenance(1));
+ }
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr
new file mode 100644
index 000000000000..32e92319cdf3
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr
@@ -0,0 +1,13 @@
+error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C"
+ --> tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs:LL:CC
+ |
+LL | assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
+ |
+ = 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
+ = note: this error occurred while pushing a call frame onto an empty stack
+ = note: the span indicates which code caused the function to be called, but may not be the literal call site
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs
index 1e10f682e71e..3629e4387e7f 100644
--- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs
+++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs
@@ -1,5 +1,4 @@
unsafe extern "C" fn ctor() -> i32 {
- //~^ERROR: calling a function with return type i32 passing return place of type ()
0
}
@@ -31,6 +30,7 @@ macro_rules! ctor {
)]
#[used]
static $ident: unsafe extern "C" fn() -> i32 = $ctor;
+ //~^ERROR: calling a function with return type i32 passing return place of type ()
};
}
diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr
index 68c56044be88..1b4cd23e41a8 100644
--- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr
+++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr
@@ -1,11 +1,19 @@
error: Undefined Behavior: calling a function with return type i32 passing return place of type ()
+ --> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC
+ |
+LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
+...
+LL | ctor! { CTOR = ctor }
+ | --------------------- in this macro invocation
|
- = note: Undefined Behavior occurred here
- = note: (no span available)
= 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: this error occurred while pushing a call frame onto an empty stack
+ = note: the span indicates which code caused the function to be called, but may not be the literal call site
+ = note: this error originates in the macro `ctor` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs
new file mode 100644
index 000000000000..5d5cb749f896
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs
@@ -0,0 +1,18 @@
+//@only-target: darwin
+
+use std::{mem, ptr};
+
+extern "C" {
+ fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
+}
+
+fn register(dtor: unsafe fn(*mut u8)) {
+ unsafe {
+ _tlv_atexit(mem::transmute(dtor), ptr::null_mut());
+ //~^ERROR: calling a function with calling convention "Rust"
+ }
+}
+
+fn main() {
+ register(|_| ());
+}
diff --git a/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr
new file mode 100644
index 000000000000..0fc87f13f16d
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr
@@ -0,0 +1,13 @@
+error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C"
+ --> tests/fail/shims/macos_tlv_atexit_wrong_abi.rs:LL:CC
+ |
+LL | _tlv_atexit(mem::transmute(dtor), ptr::null_mut());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
+ |
+ = 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
+ = note: this error occurred while pushing a call frame onto an empty stack
+ = note: the span indicates which code caused the function to be called, but may not be the literal call site
+
+error: aborting due to 1 previous error
+