-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix FFI-unwind unsoundness with mixed panic mode #97235
Conversation
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
(rust-highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@@ -198,7 +198,7 @@ crate struct CrateRoot<'tcx> { | |||
extra_filename: String, | |||
hash: Svh, | |||
stable_crate_id: StableCrateId, | |||
panic_strategy: PanicStrategy, | |||
panic_strategy: Option<PanicStrategy>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would cause this to be None
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the crate is compiled with -C panic=unwind
and contains no FFI unwind calls. I.e. it does not require a particular panic runtime to be linked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems a bit odd? The panic strategy still makes a difference for other things, doesn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field should definitely be renamed (perhaps requires_panic_runtime
?), it is very confusing at the moment since "panic strategy" refers to how the current crate was compiled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#![no_std]
code doesn't require a panic runtime, but could still require a particular panic strategy for any dependent crates. For example a -Cpanic=abort
no std crate requires all dependent crates to be compiled with -Cpanic=abort
too, even though using #[panic_handler]
rather than linking a panic runtime would work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field and related query (panic_strategy(_: CrateNum)
) is only used for checking compatibility. I could rename this to required_panic_strategy
.
not sure if i'm the best person to review this r? rust-lang/compiler |
This comment has been minimized.
This comment has been minimized.
☔ The latest upstream changes (presumably #97239) made this pull request unmergeable. Please resolve the merge conflicts. |
Why is that okay? (And that documentation should be somewhere more permanent that this PR, such as in the code and maybe even ameded to the RFC or added to the reference or so.) |
@@ -397,18 +401,14 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { | |||
if let Linkage::NotLinked = *linkage { | |||
continue; | |||
} | |||
if desired_strategy == PanicStrategy::Abort { | |||
continue; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a key part of the PR, right? That's where previously we skipped a check that we do not skip any more now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorts of. Previously any crate can be linked to panic-abort; this line only has to be removed because the required panic strategy becomes three-value. You can think of the all previous PanicStrategy::Unwind
maps to None
in this PR.
Trying to answer my own question... Is it correct that this PR ensures the following property? If anywhere in the crate graph is a panic=abort crate, then all call sites where foreign exceptions could enter the Rust part of the program are in a panic=abort crate, and hence will lead to immediate abort. There will also be no exceptions generated from Rust itself, and hence it is correct that a "Rust" ABI function can never unwind. |
@@ -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))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't core
and alloc
need the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually want to make it a default for compiling std and all its dependencies -- but not sure how.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a thread in t-libs. The lint should be denied for std and its dependencies but not denied for panic runtimes, and it seems that this isn't quite achievement at the moment.
Cc @Amanieu |
@@ -954,6 +954,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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be called twice: here and in mir_const
. Is this intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This query uses mir_built
, which will be stolen later. So I followed the same pattern as check_unsafety
(which also uses mir_built
, by making sure it's evaluated before a query that could steal it.
@@ -31,11 +31,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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a change in behavior; is_fn_like
returns false
for a Ctor
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine; ctor won't call other functions.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@bors rollup=never |
Currently the lint only fires when It's possible to have |
@bors r+ |
📌 Commit 0cf28dc has been approved by |
☀️ Test successful - checks-actions |
Finished benchmarking commit (6a10920): comparison url. Instruction count
Max RSS (memory usage)Results
CyclesResults
If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. Next Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression Footnotes |
There is a new query to be executed (and cached) for each MIR function body, so the regression is not unexpected. |
Fix outdated comment of `fn_can_unwind` The first part is outdated since rust-lang#96473, and the second part is outdated since rust-lang#97235
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 intopanic-abort
if it contains a call toC-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 underc_unwind
feature gate) to flag any FFI unwind calls that will cause the linkable panic runtime be restricted.In summary:
Fix #96926
@rustbot label: T-compiler F-c_unwind