Skip to content
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

c_unwind full stabilization request: change in extern "C" behavior #115285

Closed
BatmanAoD opened this issue Aug 27, 2023 · 28 comments · Fixed by #116088
Closed

c_unwind full stabilization request: change in extern "C" behavior #115285

BatmanAoD opened this issue Aug 27, 2023 · 28 comments · Fixed by #116088
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@BatmanAoD
Copy link
Member

BatmanAoD commented Aug 27, 2023

Tracking issue: #74990

This is a separate issue to enable using the FCP bot a second time. The request-for-stabilization comment is duplicated below, without modification.

RFC "C-unwind ABI": rust-lang/rfcs#2945

Feature gate to be stabilized: #![feature(c_unwind)]

Stabilization PR: #116088

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 27, 2023
@BatmanAoD
Copy link
Member Author

Request for Stabilization

This is a request for full stabilization of the c_unwind feature, RFC-2945. The behavior of non-"Rust", non-unwind ABIs (such as extern "C") will be modified to close soundness holes caused by permitting stack-unwinding to cross FFI boundaries that do not support unwinding.

Summary

When using panic=unwind, if a Rust function marked extern "C" panics (and that panic is not caught), the runtime will now abort.

Previously, the runtime would simply attempt to unwind the caller's stack, but the behavior when doing so was undefined, because extern "C" functions are optimized with the assumption that they cannot unwind (i.e. in rustc, they are given the LLVM nounwind annotation).

This affects existing programs. If a program relies on a Rust panic "escaping" from extern "C":

  • It is currently unsound.
  • Once this feature is stabilized, the program will crash when this occurs, whereas previously it may have appeared to work as expected.
  • Replacing extern "x" with extern "x-unwind" will produce the intended behavior without the unsoundness.

The behavior of function calls using extern "C" is unchanged; thus, it is still undefined behavior to call a C++ function that throws an exception using the extern "C" ABI, even when compiling with panic=unwind.

Changes since the RFC

None.

Unresolved questions

This feature does not affect the behavior of pthread_exit or longjmp, so stabilization will neither break existing code using these features nor provide any soundness guarantee.

Tests

"C" guaranteed to abort on panic

This test verifies that an extern "C" function that panic!s will always abort if the panic would otherwise "escape".

Documentation

The documentation PRs for this feature did not distinguish between the initial partially-stabilized behavior and the fully-stabilized behavior, so they already include the modifications to non-unwind ABIs.

I've also opened an issue to discuss adding a brief note about this feature in the Book.

@joshtriplett joshtriplett added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Aug 27, 2023
@joshtriplett
Copy link
Member

@rfcbot merge

@rfcbot
Copy link

rfcbot commented Aug 27, 2023

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Aug 27, 2023
@nbdd0121
Copy link
Contributor

cc @rust-lang/wg-ffi-unwind

@compiler-errors compiler-errors removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 27, 2023
@tmandry
Copy link
Member

tmandry commented Sep 1, 2023

  • Once this feature is stabilized, the program will crash when this occurs, whereas previously it may have appeared to work as expected.

Do we have a crater run showing the impact of this? I'd prefer to give the ecosystem time to update their code ahead of crashing everyone's programs (even if they're technically already broken).

That said, we will need some way of alerting all the broken libraries.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Sep 1, 2023

We could do the crater run on the PR (still under preparation, sorry!)

@BatmanAoD
Copy link
Member Author

I do think it makes sense to do a crater run before actually approving the stabilization.

@traviscross
Copy link
Contributor

@rustbot labels +I-lang-nominated

Nominating so we can discuss what needs to happen to move this forward.

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Oct 24, 2023
@traviscross
Copy link
Contributor

@rustbot labels -I-lang-nominated

@rustbot rustbot removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Oct 25, 2023
@nikomatsakis
Copy link
Contributor

I'm in favor of doing this. At worst we can tie it to the edition.

@traviscross
Copy link
Contributor

The situation seems to be that we're waiting on #116088 for the crater run, and that PR is waiting on #113923 to land.

@BatmanAoD
Copy link
Member Author

@traviscross That's correct; sorry for not linking to those myself.

bors added a commit to rust-lang-ci/rust that referenced this issue Dec 10, 2023
Stabilise `c_unwind`

Fix rust-lang#74990
Fix rust-lang#115285

Marking as draft PR for now due to `compiler_builtins` issues

r? `@Amanieu`
bors added a commit to rust-lang-ci/rust that referenced this issue Dec 26, 2023
Stabilise `c_unwind`

Fix rust-lang#74990
Fix rust-lang#115285

Marking as draft PR for now due to `compiler_builtins` issues

r? `@Amanieu`
@nbdd0121
Copy link
Contributor

Crater run is completed. I have triaged all crater failures and determined they are either flaky test, or broken crate, or are expected failure due to the change to enforce extern "C" to be nounwind.

@traviscross
Copy link
Contributor

@rustbot labels +I-lang-nominated

Nominating for discussion as it seems we had been waiting on a crater run and analysis that now has been completed.

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Feb 3, 2024
@RalfJung
Copy link
Member

RalfJung commented Feb 3, 2024

However, #113923 has also been reverted, so currently we can't stabilize this yet AFAIK.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Feb 3, 2024

I think that's should only be blocking the PR, not the FCP?

@BatmanAoD
Copy link
Member Author

BatmanAoD commented Mar 6, 2024

expected failure due to the change to enforce extern "C" to be nounwind

I think this is what we were specifically worried about, isn't it? How widespread is this?

From your comment, it looks like it's these crates?

  • ad9361-rs
  • cashweb-secp256k1
  • consistenttime
  • lv2-worker
  • mujs
  • quest_bind
  • sawp-ffi
  • near_sdk
  • zcash

Any idea if the maintainers of these crates know about the upcoming change?

@cratelyn
Copy link

cratelyn commented Mar 6, 2024

the zcash crate looks to be https://crates.io/crates/zcash a namesquatting crate. it is version 0.0.0, hasn't been updated in 5 years, and the associated repository has since been deleted.

p.s. so excited to see this work in the final comment period! thank you all again for helping mentor my work on #76570. 💟

@bjorn3
Copy link
Member

bjorn3 commented Mar 6, 2024

The crater report contains regressions for several zcash related git repos: https://crater-reports.s3.amazonaws.com/pr-116088-2/index.html Several at least are forks of the upstream zcash, for which no regressions are reported. So it may well be that they were forked before it was fixed in upstream.

@traviscross
Copy link
Contributor

@rustbot labels -I-lang-nominated

We discussed this in triage today with the result that this in now entering FCP. Thanks to @BatmanAoD for working to push this forward.

@rustbot rustbot removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Mar 6, 2024
@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Mar 16, 2024
@rfcbot
Copy link

rfcbot commented Mar 16, 2024

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

@rfcbot rfcbot added the to-announce Announce this issue on triage meeting label Mar 16, 2024
@CAD97
Copy link
Contributor

CAD97 commented Mar 16, 2024

Small thing: I find it somewhat surprising the exact manner in which unwinds become aborts in extern "C" fn. Specifically, the current behavior is that each unwinding edge in the extern "C" fn is set to terminate(abi), resulting in that any locals of the extern "C" fn itself are not dropped. The behavior that I expected is achievable by immediately delegating to a function with an unwinding ABI — that unwinding continues as normal up until it reaches the extern "C" boundary, at which point it aborts. (In MIR terms, generate cleanup bbs as normal, only replacing unwind continue with unwind terminate(abi), leaving any unwind: bbN as-is.)

Further refining, it surprises me that wrapping a function body in an immediately invoked closure changes semantics. I do not expect the changed ABI in the signature to change the semantics of the contained body.

I could live with this, as the developer actually technically has more control in this setup, and it's lower overhead to abort more eagerly, but it still feels a bit wrong, and performance of the about-to-abort edge isn't particularly important. Any optimization barriers to the happy path are mostly still present due to the unwind edge existing at all.

(Sorry for just missing FCP on this observation... I said something similar in the discussion around drop unwinds when I determined this is how it works, but didn't think to mention it here as well for some reason.)

nbdd0121 notes that while this is the case for the Itanium unwind ABI, MSVC+SEH produces an immediate abort at the unwind source instead. This doesn't exactly match the behavior my testing gets, but it is at least different for SEH than Itanium.

@RalfJung
Copy link
Member

RalfJung commented Mar 30, 2024

I agree that's surprising, and opened an issue: #123231.

Not sure if that's something we need to resolve before stabilization. However if we want to keep the current behavior we definitely need to document somewhere that calling these destructors is not guaranteed.

@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Apr 4, 2024
@daira
Copy link
Contributor

daira commented May 28, 2024

The crater report contains regressions for several zcash related git repos: https://crater-reports.s3.amazonaws.com/pr-116088-2/index.html Several at least are forks of the upstream zcash, for which no regressions are reported. So it may well be that they were forked before it was fixed in upstream.

Speaking as ECC's engineering manager responsible for zcashd and librustzcash, I strongly support stabilization of this change. In fact I have been bitterly complaining, with this issue as one of the examples, about the time it takes to fix soundness bugs in Rust. So it would be rather ironic if Zcash-related code were any part of the reason you were not doing so in this case (although I cannot see why it would be).

zcashd pins a specific Rust version, so there is no significant risk. If it breaks us, we will fix it before changing that pin — or not, because zcashd is being deprecated anyway.

We also have an issue to change all our uses of "C" to "C-unwind" in librustzcash; the only reason why that was not prioritized is that there appeared to be no significant progress on the full stabilization, which is precisely the thing that would make "C-unwind" useful to us.

@BatmanAoD
Copy link
Member Author

@daira

Believe me, I sympathize with the pain of how long this feature/fix has taken.

We also have an issue to change all our uses of "C" to "C-unwind" in librustzcash; the only reason why that was not prioritized is that there appeared to be no significant progress on the full stabilization, which is precisely the thing that would make "C-unwind" useful to us.

Sorry, I don't understand this dilemma; the "full stabilization" will only affect "C". The "C-unwind" behavior, as described in the stabilization request and RFC, is already in place.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jun 7, 2024
Stabilise `c_unwind`

Fix rust-lang#74990
Fix rust-lang#115285 (that's also where FCP is happening)

Marking as draft PR for now due to `compiler_builtins` issues

r? `@Amanieu`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jun 7, 2024
Stabilise `c_unwind`

Fix rust-lang#74990
Fix rust-lang#115285 (that's also where FCP is happening)

Marking as draft PR for now due to `compiler_builtins` issues

r? ``@Amanieu``
bors added a commit to rust-lang-ci/rust that referenced this issue Jun 9, 2024
Stabilise `c_unwind`

Fix rust-lang#74990
Fix rust-lang#115285 (that's also where FCP is happening)

Marking as draft PR for now due to `compiler_builtins` issues

r? `@Amanieu`
@bors bors closed this as completed in 1aaab8b Jun 20, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Sep 28, 2024
… r=Mark-Simulacrum

Update `catch_unwind` doc comments for `c_unwind`

Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose.

Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP.

Related: rust-lang#74990, rust-lang#115285, rust-lang/reference#1226
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 29, 2024
…=Mark-Simulacrum

Update `catch_unwind` doc comments for `c_unwind`

Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose.

Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP.

Related: rust-lang#74990, rust-lang#115285, rust-lang/reference#1226
RalfJung pushed a commit to RalfJung/miri that referenced this issue Oct 3, 2024
…ulacrum

Update `catch_unwind` doc comments for `c_unwind`

Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose.

Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP.

Related: rust-lang/rust#74990, rust-lang/rust#115285, rust-lang/reference#1226
lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Oct 8, 2024
…ulacrum

Update `catch_unwind` doc comments for `c_unwind`

Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose.

Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP.

Related: rust-lang/rust#74990, rust-lang/rust#115285, rust-lang/reference#1226
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.