diff options
| author | bors <bors@rust-lang.org> | 2022-07-02 14:06:27 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-07-02 14:06:27 +0000 |
| commit | 6a1092056441652fe5fe5c5b422644951e6b99ce (patch) | |
| tree | 71a0aac9ad05bbf9c47458a93faabe813b34cd3b | |
| parent | 0075bb4fad68e64b6d1be06bf2db366c30bc75e1 (diff) | |
| parent | 0cf28dc95d8396aa207bddd2d4424963b64d0c16 (diff) | |
| download | rust-6a1092056441652fe5fe5c5b422644951e6b99ce.tar.gz rust-6a1092056441652fe5fe5c5b422644951e6b99ce.zip | |
Auto merge of #97235 - nbdd0121:unwind, r=Amanieu
Fix FFI-unwind unsoundness with mixed panic mode
UB maybe introduced when an FFI exception happens in a `C-unwind` foreign function and it propagates through a crate compiled with `-C panic=unwind` into a crate compiled with `-C panic=abort` (#96926).
To prevent this unsoundness from happening, we will disallow a crate compiled with `-C panic=unwind` to be linked into `panic-abort` *if* it contains a call to `C-unwind` foreign function or function pointer. If no such call exists, then we continue to allow such mixed panic mode linking because it's sound (and stable). In fact we still need the ability to do mixed panic mode linking for std, because we only compile std once with `-C panic=unwind` and link it regardless panic strategy.
For libraries that wish to remain compile-once-and-linkable-to-both-panic-runtimes, a `ffi_unwind_calls` lint is added (gated under `c_unwind` feature gate) to flag any FFI unwind calls that will cause the linkable panic runtime be restricted.
In summary:
```rust
#![warn(ffi_unwind_calls)]
mod foo {
#[no_mangle]
pub extern "C-unwind" fn foo() {}
}
extern "C-unwind" {
fn foo();
}
fn main() {
// Call to Rust function is fine regardless ABI.
foo::foo();
// Call to foreign function, will cause the crate to be unlinkable to panic-abort if compiled with `-Cpanic=unwind`.
unsafe { foo(); }
//~^ WARNING call to foreign function with FFI-unwind ABI
let ptr: extern "C-unwind" fn() = foo::foo;
// Call to function pointer, will cause the crate to be unlinkable to panic-abort if compiled with `-Cpanic=unwind`.
ptr();
//~^ WARNING call to function pointer with FFI-unwind ABI
}
```
Fix #96926
`@rustbot` label: T-compiler F-c_unwind
27 files changed, 366 insertions, 39 deletions
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 502afa493fe..5b263aded9c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -972,6 +972,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { if !tcx.sess.opts.debugging_opts.thir_unsafeck { rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); } + tcx.ensure().has_ffi_unwind_calls(def_id); if tcx.hir().body_const_context(def_id).is_some() { tcx.ensure() diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index d52455e2576..40601bb5aad 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3231,6 +3231,7 @@ declare_lint_pass! { UNEXPECTED_CFGS, DEPRECATED_WHERE_CLAUSE_LOCATION, TEST_UNSTABLE_LINT, + FFI_UNWIND_CALLS, ] } @@ -3896,3 +3897,42 @@ declare_lint! { "this unstable lint is only for testing", @feature_gate = sym::test_unstable_lint; } + +declare_lint! { + /// The `ffi_unwind_calls` lint detects calls to foreign functions or function pointers with + /// `C-unwind` or other FFI-unwind ABIs. + /// + /// ### Example + /// + /// ```rust,ignore (need FFI) + /// #![feature(ffi_unwind_calls)] + /// #![feature(c_unwind)] + /// + /// # mod impl { + /// # #[no_mangle] + /// # pub fn "C-unwind" fn foo() {} + /// # } + /// + /// extern "C-unwind" { + /// fn foo(); + /// } + /// + /// fn bar() { + /// unsafe { foo(); } + /// let ptr: unsafe extern "C-unwind" fn() = foo; + /// unsafe { ptr(); } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// For crates containing such calls, if they are compiled with `-C panic=unwind` then the + /// produced library cannot be linked with crates compiled with `-C panic=abort`. For crates + /// that desire this ability it is therefore necessary to avoid such calls. + pub FFI_UNWIND_CALLS, + Allow, + "call to foreign functions or function pointers with FFI-unwind ABI", + @feature_gate = sym::c_unwind; +} diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 555db5846ed..cb50c0fb738 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -748,7 +748,7 @@ impl<'a> CrateLoader<'a> { if !data.is_panic_runtime() { self.sess.err(&format!("the crate `{}` is not a panic runtime", name)); } - if data.panic_strategy() != desired_strategy { + if data.required_panic_strategy() != Some(desired_strategy) { self.sess.err(&format!( "the crate `{}` does not have the panic \ strategy `{}`", diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 245b2076ebc..770d164894a 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -60,7 +60,6 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use rustc_session::cstore::CrateDepKind; use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; -use rustc_target::spec::PanicStrategy; pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies { tcx.sess @@ -367,14 +366,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { prev_name, cur_name )); } - panic_runtime = Some((cnum, tcx.panic_strategy(cnum))); + panic_runtime = Some(( + cnum, + tcx.required_panic_strategy(cnum).unwrap_or_else(|| { + bug!("cannot determine panic strategy of a panic runtime"); + }), + )); } } // If we found a panic runtime, then we know by this point that it's the // only one, but we perform validation here that all the panic strategy // compilation modes for the whole DAG are valid. - if let Some((cnum, found_strategy)) = panic_runtime { + if let Some((runtime_cnum, found_strategy)) = panic_runtime { let desired_strategy = sess.panic_strategy(); // First up, validate that our selected panic runtime is indeed exactly @@ -384,7 +388,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { "the linked panic runtime `{}` is \ not compiled with this crate's \ panic strategy `{}`", - tcx.crate_name(cnum), + tcx.crate_name(runtime_cnum), desired_strategy.desc() )); } @@ -397,18 +401,14 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { if let Linkage::NotLinked = *linkage { continue; } - if desired_strategy == PanicStrategy::Abort { - continue; - } let cnum = CrateNum::new(i + 1); - if tcx.is_compiler_builtins(cnum) { + if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) { continue; } - let found_strategy = tcx.panic_strategy(cnum); - if desired_strategy != found_strategy { + if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy { sess.err(&format!( - "the crate `{}` is compiled with the \ + "the crate `{}` requires \ panic strategy `{}` which is \ incompatible with this crate's \ strategy of `{}`", diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 3280fd5c310..f0ccf02c9fa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1758,8 +1758,8 @@ impl CrateMetadata { self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind)) } - pub(crate) fn panic_strategy(&self) -> PanicStrategy { - self.root.panic_strategy + pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> { + self.root.required_panic_strategy } pub(crate) fn needs_panic_runtime(&self) -> bool { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0bea2a10da8..565eec18ea9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -246,7 +246,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, has_global_allocator => { cdata.root.has_global_allocator } has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } - panic_strategy => { cdata.root.panic_strategy } + required_panic_strategy => { cdata.root.required_panic_strategy } panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy } extern_crate => { let r = *cdata.extern_crate.lock(); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 75286b89068..bb4b502bded 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -665,7 +665,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { triple: tcx.sess.opts.target_triple.clone(), hash: tcx.crate_hash(LOCAL_CRATE), stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), - panic_strategy: tcx.sess.panic_strategy(), + required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE), panic_in_drop_strategy: tcx.sess.opts.debugging_opts.panic_in_drop, edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a58c0e68ee3..a50eb2a71cf 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -217,7 +217,7 @@ pub(crate) struct CrateRoot { extra_filename: String, hash: Svh, stable_crate_id: StableCrateId, - panic_strategy: PanicStrategy, + required_panic_strategy: Option<PanicStrategy>, panic_in_drop_strategy: PanicStrategy, edition: Edition, has_global_allocator: bool, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a1065eef850..294f56d16b1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1356,9 +1356,13 @@ rustc_queries! { desc { "query a crate is `#![profiler_runtime]`" } separate_provide_extern } - query panic_strategy(_: CrateNum) -> PanicStrategy { + query has_ffi_unwind_calls(key: LocalDefId) -> bool { + desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } + } + query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> { fatal_cycle - desc { "query a crate's configured panic strategy" } + desc { "query a crate's required panic strategy" } separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 11980382ffd..2c8389e532d 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -1,6 +1,5 @@ use crate::MirPass; use rustc_ast::InlineAsmOptions; -use rustc_hir::def::DefKind; use rustc_middle::mir::*; use rustc_middle::ty::layout; use rustc_middle::ty::{self, TyCtxt}; @@ -31,11 +30,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { // We don't simplify the MIR of constants at this time because that // namely results in a cyclic query when we call `tcx.type_of` below. - let is_function = match kind { - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure(def_id), - }; - if !is_function { + if !kind.is_fn_like() { return; } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs new file mode 100644 index 00000000000..7728fdaffb0 --- /dev/null +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -0,0 +1,170 @@ +use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; +use rustc_middle::mir::*; +use rustc_middle::ty::layout; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::lint::builtin::FFI_UNWIND_CALLS; +use rustc_target::spec::abi::Abi; +use rustc_target::spec::PanicStrategy; + +fn abi_can_unwind(abi: Abi) -> bool { + use Abi::*; + match abi { + C { unwind } + | System { unwind } + | Cdecl { unwind } + | Stdcall { unwind } + | Fastcall { unwind } + | Vectorcall { unwind } + | Thiscall { unwind } + | Aapcs { unwind } + | Win64 { unwind } + | SysV64 { unwind } => unwind, + PtxKernel + | Msp430Interrupt + | X86Interrupt + | AmdGpuKernel + | EfiApi + | AvrInterrupt + | AvrNonBlockingInterrupt + | CCmseNonSecureCall + | Wasm + | RustIntrinsic + | PlatformIntrinsic + | Unadjusted => false, + Rust | RustCall | RustCold => true, + } +} + +// Check if the body of this def_id can possibly leak a foreign unwind into Rust code. +fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { + debug!("has_ffi_unwind_calls({local_def_id:?})"); + + // Only perform check on functions because constants cannot call FFI functions. + let def_id = local_def_id.to_def_id(); + let kind = tcx.def_kind(def_id); + if !kind.is_fn_like() { + return false; + } + + let body = &*tcx.mir_built(ty::WithOptConstParam::unknown(local_def_id)).borrow(); + + let body_ty = tcx.type_of(def_id); + let body_abi = match body_ty.kind() { + ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Generator(..) => Abi::Rust, + _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), + }; + let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi); + + // Foreign unwinds cannot leak past functions that themselves cannot unwind. + if !body_can_unwind { + return false; + } + + let mut tainted = false; + + for block in body.basic_blocks() { + if block.is_cleanup { + continue; + } + let Some(terminator) = &block.terminator else { continue }; + let TerminatorKind::Call { func, .. } = &terminator.kind else { continue }; + + let ty = func.ty(body, tcx); + let sig = ty.fn_sig(tcx); + + // Rust calls cannot themselves create foreign unwinds. + if let Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() { + continue; + }; + + let fn_def_id = match ty.kind() { + ty::FnPtr(_) => None, + &ty::FnDef(def_id, _) => { + // Rust calls cannot themselves create foreign unwinds. + if !tcx.is_foreign_item(def_id) { + continue; + } + Some(def_id) + } + _ => bug!("invalid callee of type {:?}", ty), + }; + + if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) && abi_can_unwind(sig.abi()) { + // We have detected a call that can possibly leak foreign unwind. + // + // Because the function body itself can unwind, we are not aborting this function call + // upon unwind, so this call can possibly leak foreign unwind into Rust code if the + // panic runtime linked is panic-abort. + + let lint_root = body.source_scopes[terminator.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + let span = terminator.source_info.span; + + tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| { + let msg = match fn_def_id { + Some(_) => "call to foreign function with FFI-unwind ABI", + None => "call to function pointer with FFI-unwind ABI", + }; + let mut db = lint.build(msg); + db.span_label(span, msg); + db.emit(); + }); + + tainted = true; + } + } + + tainted +} + +fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrategy> { + assert_eq!(cnum, LOCAL_CRATE); + + if tcx.is_panic_runtime(LOCAL_CRATE) { + return Some(tcx.sess.panic_strategy()); + } + + if tcx.sess.panic_strategy() == PanicStrategy::Abort { + return Some(PanicStrategy::Abort); + } + + for def_id in tcx.hir().body_owners() { + if tcx.has_ffi_unwind_calls(def_id) { + // Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls` + // MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception + // can enter Rust through these sites. + // + // On the other hand, crates compiled with `-C panic=abort` expects that all Rust + // functions cannot unwind (whether it's caused by Rust panic or foreign exception), + // and this expectation mismatch can cause unsoundness (#96926). + // + // To address this issue, we enforce that if FFI-unwind calls are used in a crate + // compiled with `panic=unwind`, then the final panic strategy must be `panic=unwind`. + // This will ensure that no crates will have wrong unwindability assumption. + // + // It should be noted that it is okay to link `panic=unwind` into a `panic=abort` + // program if it contains no FFI-unwind calls. In such case foreign exception can only + // enter Rust in a `panic=abort` crate, which will lead to an abort. There will also + // be no exceptions generated from Rust, so the assumption which `panic=abort` crates + // make, that no Rust function can unwind, indeed holds for crates compiled with + // `panic=unwind` as well. In such case this function returns `None`, indicating that + // the crate does not require a particular final panic strategy, and can be freely + // linked to crates with either strategy (we need such ability for libstd and its + // dependencies). + return Some(PanicStrategy::Unwind); + } + } + + // This crate can be linked with either runtime. + None +} + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { has_ffi_unwind_calls, required_panic_strategy, ..*providers }; +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b7caa61ef07..12fcb299ce3 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -59,6 +59,7 @@ pub mod dump_mir; mod early_otherwise_branch; mod elaborate_box_derefs; mod elaborate_drops; +mod ffi_unwind_calls; mod function_item_references; mod generator; mod inline; @@ -98,6 +99,7 @@ pub fn provide(providers: &mut Providers) { check_unsafety::provide(providers); check_packed_ref::provide(providers); coverage::query::provide(providers); + ffi_unwind_calls::provide(providers); shim::provide(providers); *providers = Providers { mir_keys, @@ -223,6 +225,9 @@ fn mir_const<'tcx>( } } + // has_ffi_unwind_calls query uses the raw mir, so make sure it is run. + tcx.ensure().has_ffi_unwind_calls(def.did); + let mut body = tcx.mir_built(def).steal(); rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ba76ee31b42..252b7545a99 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -210,6 +210,8 @@ #![allow(unused_lifetimes)] // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] +// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` +#![cfg_attr(not(bootstrap), deny(ffi_unwind_calls))] // std may use features in a platform-specific way #![allow(unused_features)] #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))] diff --git a/src/test/ui/panic-runtime/auxiliary/needs-abort.rs b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs new file mode 100644 index 00000000000..8fad49b5e9d --- /dev/null +++ b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs @@ -0,0 +1,5 @@ +// compile-flags:-C panic=abort +// no-prefer-dynamic + +#![crate_type = "rlib"] +#![no_std] diff --git a/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs new file mode 100644 index 00000000000..d555b531986 --- /dev/null +++ b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs @@ -0,0 +1,13 @@ +// compile-flags:-C panic=unwind +// no-prefer-dynamic + +#![crate_type = "rlib"] +#![no_std] +#![feature(c_unwind)] + +extern "C-unwind" fn foo() {} + +fn bar() { + let ptr: extern "C-unwind" fn() = foo; + ptr(); +} diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.rs b/src/test/ui/panic-runtime/need-abort-got-unwind.rs new file mode 100644 index 00000000000..c72fb96e357 --- /dev/null +++ b/src/test/ui/panic-runtime/need-abort-got-unwind.rs @@ -0,0 +1,9 @@ +// build-fail +// needs-unwind +// error-pattern:is incompatible with this crate's strategy of `unwind` +// aux-build:needs-abort.rs +// ignore-wasm32-bare compiled with panic=abort by default + +extern crate needs_abort; + +fn main() {} diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.stderr b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr new file mode 100644 index 00000000000..d29c7875fd0 --- /dev/null +++ b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind` + +error: aborting due to previous error + diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.rs b/src/test/ui/panic-runtime/need-unwind-got-abort.rs new file mode 100644 index 00000000000..6752ecf90d2 --- /dev/null +++ b/src/test/ui/panic-runtime/need-unwind-got-abort.rs @@ -0,0 +1,9 @@ +// build-fail +// error-pattern:is incompatible with this crate's strategy of `abort` +// aux-build:needs-unwind.rs +// compile-flags:-C panic=abort +// no-prefer-dynamic + +extern crate needs_unwind; + +fn main() {} diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.stderr b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr new file mode 100644 index 00000000000..4c71df3ebc1 --- /dev/null +++ b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` + +error: aborting due to previous error + diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr index 4af754c81f9..7f4a8ed290e 100644 --- a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr +++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr @@ -2,9 +2,7 @@ error: cannot link together two panic runtimes: panic_runtime_unwind and panic_r error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind` -error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` +error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind` -error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs index c48caaf0790..23bfea6af15 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs +++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs @@ -1,6 +1,6 @@ // build-fail // needs-unwind -// error-pattern:is incompatible with this crate's strategy of `unwind` +// error-pattern:is not compiled with this crate's panic strategy `unwind` // aux-build:panic-runtime-abort.rs // aux-build:panic-runtime-lang-items.rs // ignore-wasm32-bare compiled with panic=abort by default diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr index d4fd2cca81f..d306ce6c5ea 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr +++ b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr @@ -1,6 +1,4 @@ error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind` -error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr index 364a27a24eb..014437b7f1b 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr +++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr @@ -1,8 +1,6 @@ error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind` -error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` +error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind` -error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs index f02a368d4e0..ba72f74f20c 100644 --- a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs @@ -1,6 +1,10 @@ // Test that the "C-unwind" ABI is feature-gated, and cannot be used when the // `c_unwind` feature gate is not used. +#![allow(ffi_unwind_calls)] +//~^ WARNING unknown lint: `ffi_unwind_calls` +//~| WARNING unknown lint: `ffi_unwind_calls` + extern "C-unwind" fn f() {} //~^ ERROR C-unwind ABI is experimental and subject to change [E0658] diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr index f4c785a235f..a67f46cd2e3 100644 --- a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr @@ -1,5 +1,16 @@ +warning: unknown lint: `ffi_unwind_calls` + --> $DIR/feature-gate-c-unwind.rs:4:1 + | +LL | #![allow(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_lints)]` on by default + = note: the `ffi_unwind_calls` lint is unstable + = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + error[E0658]: C-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-c-unwind.rs:4:8 + --> $DIR/feature-gate-c-unwind.rs:8:8 | LL | extern "C-unwind" fn f() {} | ^^^^^^^^^^ @@ -7,6 +18,16 @@ LL | extern "C-unwind" fn f() {} = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information = help: add `#![feature(c_unwind)]` to the crate attributes to enable -error: aborting due to previous error +warning: unknown lint: `ffi_unwind_calls` + --> $DIR/feature-gate-c-unwind.rs:4:1 + | +LL | #![allow(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `ffi_unwind_calls` lint is unstable + = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + +error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs new file mode 100644 index 00000000000..dadf4b12187 --- /dev/null +++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs @@ -0,0 +1,27 @@ +// build-pass +// needs-unwind +// ignore-wasm32-bare compiled with panic=abort by default + +#![feature(c_unwind)] +#![warn(ffi_unwind_calls)] + +mod foo { + #[no_mangle] + pub extern "C-unwind" fn foo() {} +} + +extern "C-unwind" { + fn foo(); +} + +fn main() { + // Call to Rust function is fine. + foo::foo(); + // Call to foreign function should warn. + unsafe { foo(); } + //~^ WARNING call to foreign function with FFI-unwind ABI + let ptr: extern "C-unwind" fn() = foo::foo; + // Call to function pointer should also warn. + ptr(); + //~^ WARNING call to function pointer with FFI-unwind ABI +} diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr new file mode 100644 index 00000000000..ed41cb74623 --- /dev/null +++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr @@ -0,0 +1,20 @@ +warning: call to foreign function with FFI-unwind ABI + --> $DIR/ffi-unwind-calls-lint.rs:21:14 + | +LL | unsafe { foo(); } + | ^^^^^ call to foreign function with FFI-unwind ABI + | +note: the lint level is defined here + --> $DIR/ffi-unwind-calls-lint.rs:6:9 + | +LL | #![warn(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^ + +warning: call to function pointer with FFI-unwind ABI + --> $DIR/ffi-unwind-calls-lint.rs:25:5 + | +LL | ptr(); + | ^^^^^ call to function pointer with FFI-unwind ABI + +warning: 2 warnings emitted + |
