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

Add std::panic::drop_unwind #85927

Closed
wants to merge 1 commit into from

Conversation

SabrinaJewson
Copy link
Contributor

A footgun in std::panic::catch_unwind is that panic payloads can panic when dropped. For example, this code:

let _ = panic::catch_unwind(user_code);

does not guarantee that unwinds will not occur in the outer function, because the user code could look like this:

struct PanicOnDrop;
impl Drop for PanicOnDrop {
    fn drop(&mut self) {
        panic!();
    }
}
panic_any(PanicOnDrop);

This has caused many soundness bugs for me in the past, and I have encountered soundness bugs in other crates because of this.

The solution is to add a new function, std::panic::drop_unwind, that instead of returning a Result<T, Box<dyn Any + Send>> returns a Result<T, ()>. Panic payloads are safely dropped within the function by converting panics to aborts (it's such a rare case there's no reason to try and recover).

@rust-highfive
Copy link
Collaborator

r? @m-ou-se

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 2, 2021
@m-ou-se m-ou-se added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jun 2, 2021
@m-ou-se
Copy link
Member

m-ou-se commented Jun 5, 2021

That's quite a subtle but significant issue! I've opened #86027 for the issue.

Adding drop_unwind makes it easier to do it correctly, but won't fix all the cases where catch_unwind is used. Maybe we should find a way to work around this, or produce a warning for the issue or something.

@crlf0710 crlf0710 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 26, 2021
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 12, 2021
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 31, 2021
@bors
Copy link
Contributor

bors commented Aug 1, 2021

☔ The latest upstream changes (presumably #84662) made this pull request unmergeable. Please resolve the merge conflicts.

@joelpalmer joelpalmer added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 17, 2021
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 6, 2021
@JohnCSimon
Copy link
Member

JohnCSimon commented Sep 6, 2021

Ping from triage:
@KaiJewson can you please address the merge conflict?

After you've done that please set the PR to S-waiting-on-review

@bjorn3
Copy link
Member

bjorn3 commented Sep 11, 2021

@rustbot ready

@rustbot
Copy link
Collaborator

rustbot commented Sep 11, 2021

@m-ou-se

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 11, 2021
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 28, 2021
@dtolnay dtolnay removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 3, 2021
@dtolnay dtolnay added the S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. label Oct 3, 2021
Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking as S-blocked on the discussion that is ongoing in #86027. A few alternatives are proposed. I don't think we would want to land this PR until there is some semblance of consensus around the alternative approaches.

@CAD97
Copy link
Contributor

CAD97 commented May 26, 2022

This is unstable, so it seems okay to land such that it can be used (at least by std itself) until further consensus on #86027/rust-lang/lang-team#97 is reached.

As an aside, it might be a good idea to call crate::panicking::panic_count::increase() and crate::panicking::panic_count::decrease() around the panic payload drop to get the "panicked while panicking" message rather than just an abort when hitting AbortOnDrop.

How I wrote drop_unwind
pub fn drop_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Option<R> {
    match catch_unwind(f) {
        Ok(r) => Some(r),
        Err(e) => {
            // Dropping the panic payload could panic, so prevent that.
            // Treat the thread as still panicking.
            crate::panicking::panic_count::increase();
            let e = AssertUnwindSafe(e);
            // Mark the drop closure as rustc_allocator_nounwind. This tells
            // rustc to emit its own shim to turn unwinds into aborts.
            match catch_unwind(
                #[rustc_allocator_nounwind]
                || drop(e),
            ) {
                Ok(()) => {}
                Err(_dont_drop) => {
                    // We still unwound again somehow; just abort directly.
                    rtprintpanic!("thread panicked while dropping panic payload. aborting.\n");
                    crate::sys::abort_internal();
                }
            }
            // Dropping did not panic.
            crate::panicking::panic_count::decrease();
            None
        }
    }
}

(I'm unsure if this is correct usage of #[rustc_allocator_nounwind].)

@JohnCSimon JohnCSimon added S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. and removed S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. labels Nov 27, 2022
@bors
Copy link
Contributor

bors commented Dec 29, 2022

☔ The latest upstream changes (presumably #106228) made this pull request unmergeable. Please resolve the merge conflicts.

@JohnCSimon
Copy link
Member

@SabrinaJewson
Ping from triage: I'm closing this due to inactivity, Please reopen when you are ready to continue with this.
Note: if you do please open the PR BEFORE you push to it, else you won't be able to reopen - this is a quirk of github.
Thanks for your contribution.

@rustbot label: +S-inactive

@JohnCSimon JohnCSimon closed this Jan 1, 2023
@rustbot rustbot added the S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. label Jan 1, 2023
@dtolnay dtolnay self-assigned this Mar 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.