-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Stabilize implementing panics as aborts #1513
Conversation
* Stabilize the `-Z no-landing-pads` flag under the name `-C unwind=val` * Implement a number of unstable features akin to custom allocators to swap out implementations of panic just before a final product is generated. * Add a `[profile.dev]` option to Cargo to disable unwinding.
* The compiler will have a [new stable flag](#new-compiler-flags), `-C panic` | ||
which will configure how unwinding-related code is generated. | ||
* [Two new unstable attributes](#panic-attributes) will be added to the | ||
compiler, `#![needs_panic_runtime]` and `#![panic_runtime]`. The standard |
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.
NIT: we already have a system for boolean configuration switches in attributes. That’s cfg
. I strongly propose changing the needs_panic_runtime
thing to a cfg
.
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.
Agreed. No reason for not using the general, #[cfg]
.
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.
@nagisa can you elaborate on what you're thinking? Given the way these attributes are defined below I'm not understanding how this could be implemented with #[cfg]
.
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.
@alexcrichton This, not these. Turns out that this attribute is inverse of what I thought it is at first (i.e. it declares that crate wants a runtime, rather than describe the fact that runtime is needed). Never mind me here.
Okay, I have a bunch of thoughts which I won’t be posting inline, because of GitHub’s tendency to lose the comments in the long run. Overall, I think this RFC is incorrectly conflating what current
Right, so I have two points here: with this RFC you cannot disable codegen of cleanups and continue to use the unwinding panic – which is what
Similarly, previously any crate in the dependency tree could opt-out from cleanups (as an optimisation). One crate using That being said, I do see the necessity to only have a single panicking mechanism in a final artefact, so the comment basically boils down to lack of distinction between panicking mechanism and cleanup mechanism or lack thereof. Finally, as the one who landed the |
I have some minor reservations. This only accomplishes half of the goal of creating no-unwind builds because it still uses a libstd with landing pads. Eventually we're going to get to a place where if you want this you are going to be using either a provided no-unwind std or building it yourself. It's not clear to me how that future world will work with the new If we're going to continue the pattern of |
I like the overall thrust of this RFC, and am really excited to see abort semantics one step closer to reality! My biggest concern is with the final drawback (which I talked with @alexcrichton about privately):
In particular, my feeling is that typically applications should be the one to choose the strategy, and all of their dependencies must be compatible with that strategy. (In the RFC, if any crate in the graph has abort semantics, the entire artifact does.) It's not hard to imagine pulling in some indirect dependency that silently changes from unwinding to abort, and I don't think that crate authors should be required to explicitly |
cc @jamwt, because Dropbox has long been a proponent of abort-on-panic. |
Yeah, I agree with having applications choose the strategy. As long as we're allowed to ensure that all panics abort (as users of various libraries but owners of the application), we're good. |
Oh wow, that was fast, thanks for the comments! It's true that this RFC is diverging from what I'd be fine leaving the
I'm not really sure how this is relevant, can you clarify? The whole point of the unwinding strategy on Unix today is that it's zero cost in the case where no exception is thrown, and if we had to register a handler every time we had a function call that... wouldn't be zero cost? I will say, however, that if this is just an alternate strategy of handling panics, this RFC should account for that. We would implement another
I suppose I didn't really discuss this as I'm not really sure what the discussion would be in the first place. My current interpretation of the state of MIR and such would be:
Does that make sense? Did you have other concerns? I'd definitely want to make sure that any MIR plans align well with this RFC!
I think that when rustup.rs is ready and we're distributing/managing multiple compiled modes of the standard library we'd still basically want almost everything in this RFC. The first alternative mentions this explicitly by indicating that one major change could be disallowing mixed panic modes in a DAG entirely (instead of allowing a panic runtime to link with crates compiled any which way). Are you thinking, however, that other parts of this RFC would change in the face of such a distribution mechanism? Also, the only drawback I know of with linking an unwinding libstd with an aborting application is that the object code in the standard library itself may have missed optimization opportunities based on the fact that functions will never unwind. Do you know of other drawbacks, however? Much of this RFC is foundationally built upon the idea that linking aborting applications to the libstd binaries we ship is good enough in basically all situations.
One critical portion of this RFC is the validation that the compiler performs to ensure that any sort of weird situations like this can't cause problems at runtime. For example the possible scenarios I see here are:
Basically, the compiler should always be able to provide a principled error message in these situations. Along those lines I'm not really sure what the negative interactions would be between Cargo and choosing the right libstd, but we should be able to relatively easy encourage the user to select an appropriate toolchain. Did you have other concerns in mind, however?
Yeah I'd be fine with basically anything here. I didn't put too much thought into it because they're unstable. I somewhat disagree that these will ever become defacto stable (in the panicking case). It's essentially impossible to write your own panic runtime without compiler support, so I don't think we'll see many of those any time soon. Writing a custom allocator, however, that may indeed hasten the defacto stability!
And to clarify, this RFC does allow for the case of any crate to explicitly choose a panic strategy via This, coupled with @brson's concerns, I believe, have convinced me that this needs to be a first class compiler error. Specifically if a final artifact is being produced the compiler will assert that the panic runtime selected is compiled in the same panic mode as the final artifact itself.
You can indeed! It should be as simple as: extern crate panic_abort; And then you're done! |
|
||
* The current implementation of Cargo would mean that a native implementation of | ||
the profile option would cause recompiles between `cargo build` and `cargo | ||
test` for projects that specify `panic = 'unwind'`. Is this acceptable? Should |
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.
Did you mean panic = abort
here? (Also, did you mean "naive" instead of "native"?)
If not, then can you elaborate why specifying the same unwinding strategy as the default would force a recompile?
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.
Gah oops, this is a hilarious combination of multiple types. Correct on both counts!
To clarify, does I also agree that this pattern of paired |
Regarding the need to ship two versions of std: Hypothetically, if LLVM extended to other platforms the Windows model of outlining cleanups into separate funclets, those could be placed into separate sections, and stripped out by the linker when not needed. Edit: then again, the same could be achieved with |
That's part of it, but it also enables the logic in the compiler to auto-inject a runtime if one isn't found. This is essentially solving the case where so long as you never use the standard library there's no need for a panic runtime to ever get injected. |
Yes. As I mentioned, I don't see how the cargo option aligns with a world with custom stds. There will be some - yet undesigned - mechanism in the future to specify what combination of codegen/runtime features that users want the entire world to be compiled with. This new I am further concerned that baking the unwinding configuration into the crate's configuration that we are opening the door to crates being able to specify incompatible codegen/runtime options. Things that need to be specified globally in the future:
There are probably more I'm forgetting right now. These are all related and we should have a plan to solve this issue of custom codegen/runtime components generally, not piecewise.
Bloat. |
How does this interact with panic handlers? Will panic handlers be called before an abort? |
@Amanieu No, there is no unwinding, destructors, etc. involved (hence 'abort'). |
I would like to propose an alternative design for this feature, just to throw the idea out there. The main issue with
However we could make Benefits:
Drawbacks:
|
My main concern is conflation of panicking and cleanup strategies in this RFC. Every other major issue I have with the RFC stems from that.
Any crate at the branches of call tree could use the option of explicitly leaking resources as an optimisation. As stated in the RFC itself, the cleanups are not entirely free – they consume binary space in the final executable, they increase compilation times significantly. They also compete for CPU cache, decrease instruction locality and so on. I do not see e.g. numerics crate caring about a leaked vector or two if that helps to avoid generating a bunch of code near success pathes in computation-intensive functions.
My only point here that conflating panicking and cleanup strategy doesn’t make much sense. I didn’t intend to claim it is a sensible cleanup strategy though.
Right, so for some fictional
But we do not generate
I do not see how it makes sense to generate landing pads at all if we panic by |
> from 18s) and 13% smaller (15MB to 13MB). Sizable gains! | ||
|
||
Overall, the ability to recover panics is something that needs to be decided at | ||
the application level rather than at the language level. Currently the compiler |
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.
At the application level can make sense, but what about libraries that want to opt-out because e.g. they can't recover from assertions. But what if you combine such library with applications that do want recoverable panics because they don't want to take the whole process down?
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.
Unfortunately that's essentially a situation which has no solution. The crate which wants to force panic=abort
would link to panic_abort
while the application forcing panic=unwind
would link to panic_unwind
. The compiler would detect this situation and generate an error.
I don't currently know of a way to make that kind of situation succeed to compile.
Just a small nit: The PR summary comment uses a |
I have some concerns about the ability of an application to make an informed choice about the panic strategy. Specifically, I am thinking that as a crate author I could perfectly use speculative execution and catch panics in case of issue. Today, from a user's point of view, this is completely transparent. Tomorrow, if the user decides to specify Worse, of course, is when a crate that previously was never generating/catching a panic suddenly starts doing so; as an application, it means that I need to audit each new version of the crates I pull to ensure their compatibility with In essence:
To me, as a crate author, whether I am willing to commit to support |
Rust already never guarantees destructors run though, so you can't make that kind of assumption. And when setting panic to abort, isn't "halt her application" what she'd want in the first place? On Feb 27, 2016, 10:40 -0500, [email protected], wrote:
|
@matthieu-m Of course you can do so if - and only if - you choose to ignore the warning in the Perhaps "panic=abort mode" would finally provide a strong motivation against misusing Now to my general comments on the RFC:
It's unclear to me which direction this design really chooses: While some parts of the RFC ("There will currently be two supported strategies") suggest that the set of available is clearly defined and very definitely not arbitrarily user-extensible, some of the discussion (e.g. the part I'm quoting here) appeared to be about user-defined panic strategies. This second version is also implied by the general design around (seemingly) arbitrary crates. The major difference between this area and memory allocators is that the latter generally don't require any specific language support and hence can be implemented purely as libraries (crates). This approach doesn't really seem viable for panic strategies as these care about code generation (things like invoke vs call) and are therefore always tied to hardcoded paths in the compiler unless the design is powerful enough to allow each strategy crate to hook into these compiler paths on its own, e.g. by being loaded as a compiler plugin. So to sum things up, I don't see how the current design benefits (at all) from utilizing a generic crate-based solution (versus e.g. just a compiler flag and some special piece of crate metadata that can be checked for compatibility at link-time), so I obviously don't think the downsides (conflicts etc) are worth it. |
rustc would like to not use unwinding, but print a nice ICE message before aborting. Is that going to be supported? |
One of the biggest concerns I (and others) had with stabilizing I emphatically do not believe that crate authors should use The idea behind On the other hand, handleable errors are expressed using Is is a feature not a bug that this RFC discourages crate authors from using panics to represent handle-able errors. If |
I'm going to sound like a broken record here, but the confusion over whether |
I like that name 👍 On Feb 27, 2016, 21:30 -0500, Ben [email protected], wrote:
|
Yes. It's perhaps worth distinguishing, though, between size issues and behaviour issues. It's easier to take special optimization steps on build infrastructure, so a higher bar is possible there. But as you say, this is something that can benefit many projects, so making it easy is advantageous. |
@rillian yeah I agree that separating them out is important. Behaviorally I believe Gecko needs no more than what this RFC provides. This provides a guaranteed ability to translate all Rust panics to aborts rather than stack unwinding (even through a custom method via your own panic runtime). The optimization steps, specifically for size, are tangential infrastructure related problems on our end which we intend to tackle eventually anyway :) |
The lang team did not have full quorum this week and will consider this RFC during next week's meeting; remaining in FCP until then. |
It seems that there is some kind of false genericity here - you can only really choose between two options, you can't plug in your own strategy. That would require some mechanism for augmenting the compiler (pluggable MIR pass?). I'm a bit unclear what would happen with However, as a step towards a fully generic mechanism, this RFC looks good. in particular, adopting a somewhat future proof compiler flag. The attributes sound like the right direction too, though it sounds like there will be some future discussion there. |
@nrc yeah this isn't intended to be any form of "truly general mechanism" or something like that, the compiler will reject any |
Will just libcore have |
No, the standard library will have that attribute as that's where panics are implemented. |
The additional lang items for core panics don't strike me as something we want forever. But if this RFC's proposals don't get stabilized until a more general needs/provides mechanism is investigated, I guess this is fine for now. edit heh and that's basically what I wrote a month ago #1513 (comment) So +1 for RFC if we tree treat it as experiment/stopgap. -1 for longterm as is: besides services pattern without proper support, rustc is now further entangled with std lib architecture which isn't something we generally want. |
WRT. the The idea is that a single downstream crate will be able to "bless" a particular trait implementation. Upstream crates will be able to implicitly use the yet-to-be-determined "blessed" implementation by simply calling the trait methods: This would normally be an error, because the compiler wouldn't be able to determine which implementation of The exact mechanism for blessing a trait could vary, but an easy option is to mirror the existing attributes: The advantages are extensibility and proper namespacing of blessed items. Additional fun could be had by allowing |
It's official! The @rust-lang/lang team has decided to accept this RFC. |
Tracking issue: rust-lang/rust#32837 If you'd like to keep following the development of this feature, please subscribe to that issue, thanks! :) |
This is the Cargo half of the implementation of [RFC 1513] which adds a new `profile.*.panic` option to customize the `-C panic` argument to the compiler. This is not passed by default and can otherwise be specified as `abort` or `unwind` on the nightly compiler. [RFC 1513]: rust-lang/rfcs#1513 The `profile.*.panic` option is *only* used from the top-level crate, not each crate individually. This means that applications should customize this value as they see fit, and libraries will only use their own value when they're being tested. Cargo also has specific knowledge that when *testing* a crate it can't pass `-C panic=abort` for now as the default test harness requires `panic=unwind`. This essentially just means that `cargo test` will continue to work for crates that specify `panic=abort` in Cargo.toml.
Implement the `panic` profile option This is the Cargo half of the implementation of [RFC 1513] which adds a new `profile.*.panic` option to customize the `-C panic` argument to the compiler. This is not passed by default and can otherwise be specified as `abort` or `unwind` on the nightly compiler. [RFC 1513]: rust-lang/rfcs#1513 The `profile.*.panic` option is *only* used from the top-level crate, not each crate individually. This means that applications should customize this value as they see fit, and libraries will only use their own value when they're being tested. Cargo also has specific knowledge that when *testing* a crate it can't pass `-C panic=abort` for now as the default test harness requires `panic=unwind`. This essentially just means that `cargo test` will continue to work for crates that specify `panic=abort` in Cargo.toml.
-Z no-landing-pads
flag under the name-C panic=val
implementations of panic just before a final product is generated.
[profile.dev]
option to Cargo to disable unwinding.Rendered