question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Never allow unwinding from Drop impls

See original GitHub issue

Summary

Code using catch_unwind is not typically prepared to handle an object that panics in its Drop impl. Even the standard library has had various bugs in this regard, and if the standard library doesn’t consistently get it right, we can hardly expect others to do so.

This came up in @rust-lang/libs discussion.

We discussed various ways to handle this, including potential tweaks to panic_any or catch_unwind to add special handling of types that implement Drop, but on balance we felt like it would be preferable to decide at the language level to generally not allow unwind from Drop impls. (We may not be able to universally prohibit this, but we could work towards transitioning there.)

Background reading

https://github.com/rust-lang/rust/issues/86027

About this issue

This issue corresponds to a lang-team design meeting proposal. It corresponds to a possible topic of discussion that may be scheduled for deeper discussion during one of our design meetings.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:14
  • Comments:118 (72 by maintainers)

github_iconTop GitHub Comments

7reactions
CAD97commented, May 31, 2022

Since this is one space where we are not bound by backwards-compatibility guarantees,

I’m personally not really sold on this. (Though to be fair, I’m not someone that needs to be convinced.) Forbidding unwinding from Drop::drop isn’t a soundness fix; the language level soundness fix is injecting a landing pad for nounwind contexts (e.g. extern "C" and GlobalAlloc) and the rest is (perhaps a long tail of) library fixes for collections. Unwinding from drop is generally considered a thing to avoid because it could abort even when panic=unwind, but it’s still a useful tool to have[^1].

[^1]: As a small case study, I have a crate which involves doing an FFI call that could theoretically fail for resource cleanup on drop. If the library is used correctly and the FFI bindings don’t have any bugs, then the call won’t return an error. However, I still want to check the error, especially when cfg(debug_assertions) is true. As such, on drop, if the FFI resource cleanup call returns an error, I log::error! the error, and if cfg!(debug_assertions) && !thread::unwinding(), panic!. The goal is to abort the task to a catch_unwind! landing pad because something unexpectedly went wrong, but it’s not so unrecoverable that aborting is appropriate.

Please forgive the slippery slope comparison, but saying forbidding unwinds from Drop::drop is a minor breaking change because panics in drop already could drop feels a step away from saying making library panics always abort because they already could either unwind or abort, because a consumer could call panic::always_abort().

We allow use of panic!/catch_unwind for task-level aborts if the binary author sets panic=unwind. The argument which I’m trying to convince myself isn’t just based on slippery slope FUD is that the reasoning in allowing this usage applies just as well to allowing unwinding from RAII drop if the developer knows that panic=unwind and the drop won’t be called from a panicking code path.

such a niche feature

I actively disagree with this assessment of unwinding from drop. While I agree that intentional unwinding from drop is a somewhat niche feature (though doing fallible finalization on drop may not uncommonly be written to unwrap instead of dropping the result), running downstream code from an RAII guard is imho not a niche feature.

I really don’t want to ever have to say “this shouldn’t be an RAII defer! (or equivalent) because it could panic; just put the code at the scope exit point (and hope we never add an early exit).” In fact I have one bit of API which needs to run a user trait method on a user closure return or unwind for soundness, so I need to have an RAII guard, but if I want to propogate a panic if it’s not an unwind, I’d need to duplicate the cleanup code out of the RAII guard for the happy path as well.

One point of view that I feel hasn’t been discussed enough is the significant code size and compile-time improvements that we can get by making this change.

Looking at it another way: if the current Rust default was to abort when unwinding from a drop, would we be willing to pay a 5% binary size and 10% compile-time cost to support unwinding from drops?

We can still get the benefits, though, by adding a new panic=unwind-not-from-drop profile configuration. The default panic=unwind profile would be unaffected, and binaries which are confident that they don’t unwind from drop but don’t want to be panic=abort can set panic=unwind-not-from-drop for the size benefit.

There’s already a position for code which is only sound with panic=abort (e.g. take_mut without an abort bomb) because it isn’t unwind safe. It doesn’t seem too farfetched to say that code which fails to account properly for drop unwinding is only sound when panic=unwind-not-from-drop (or panic=abort).

The one thing I’d personally want with that feature is a new function to compliment thread::panicking() which just tells you if a panic from drop would currently abort.

6reactions
Amanieucommented, Sep 9, 2021

Initial perf results: up to 10% reduction in compilation time (perf) and a 5MB (3%) reduction in the size of librustc_driver.so.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Preludes, Op.28 (Chopin, Frédéric) - IMSLP
The Impromptu by Balakirev is based on Preludes 14 and 11. Contents. [hide]. 1 Performances.
Read more >
Prelude in C-sharp minor, Op.45 (Chopin, Frédéric) - IMSLP
I provide the original scanned version and the filtered, because the filter does some changes (smoothening, sharpening borders) and some portions of the...
Read more >
Nocturnes, Op.9 (Chopin, Frédéric) - IMSLP
Publisher Info. Guiomar Novaes: Chopin: Nocturnes (Complete) — Vol I New York, N.Y.: Vox, 1956. PL 9632-1. Copyright. Public Domain - ...
Read more >
129091 - imslp-eu
ance is never to let your attention flag or waver, either musi- cally or pianistically, no matter whether you are a beginner.
Read more >
Untitled
Seducing love texts, Schwimmen frauen berlin, 59d electronic ignition, D'alembert principle ppt, Bousis chicago, Never stop traveling blog, Drop through ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found