- Feature Name:
panic_runtime
- Start Date: 2016-02-25
- RFC PR: rust-lang/rfcs#1513
- Rust Issue: rust-lang/rust#32837
Summary
Stabilize implementing
- Stabilize the
-Z no-landing-pads
flag under the name-C panic=strategy
- 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 configure how panics are implemented.実装する
Motivation
Panics in Rust have long since been implemented
- Servers can avoid避ける、回避するtakingとるdown the entire process but can instead just takeとるdown one request.
- Embedded埋め込むRust libraries can avoid避ける、回避するtakingとるdown the entire process and can instead gracefully inform the caller呼び出し側that an internal logic error occurred.起こる
- Rust applications can isolate failure from variousさまざまなcomponents.構成要素The classical example of this is Servo can display a "red X" for an image which fails to decode instead of aborting the entire browser or killing an entire page.
While these are examples where a recoverable panic is useful, there are many applications where recovering panics is undesirable or doesn't lead to anything productive:
- Rust applications which use
Result
for error handling typically一般的に、典型的にusepanic!
to indicate指し示すa fatal error, in which case the process should be taken down. - Many applications simply can't recover from an internal assertionアサーションfailure, so there's no need trying to recover it.
- To implement実装するa recoverable panic, the compiler and standard library use a method called呼び出しstack unwinding. The compiler must generate code to support this unwinding, however, and this takesとるtime in codegen and optimizers.
- Low-level applications typically一般的に、典型的にdon't use unwinding at all as there's no stack unwinder (e.g. kernels).
Note: as an idea of the compile-time and object-size savings from disabling the extra codegen, compiling Cargo as a library is 11% faster (16s 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
With such an important codegen option, however, as whether or not exceptions
Detailed design設計(する)
The major goal of this RFC is to develop a work flow around managing crates which wish to disable unwinding. This intends to set
High level design設計(する)
This section
- The compiler will have a new stable flag,
-C panic
which will configure how unwinding-related code is generated.生成する - Two new unstable attributes will be addedたすto the compiler,
#![needs_panic_runtime]
and#![panic_runtime]
. The standard library will need a runtime and will be lazily linked to a crate which has#![panic_runtime]
. - Two unstable crates tagged with
#![panic_runtime]
will be distributed as the runtime implementation実装of panicking,panic_abort
andpanic_unwind
crates. The former will translate all panics to process aborts, whereas the latter will be implemented実装するas unwinding is today, via the system stack unwinder. - Cargo will gain a new
panic
option in the[profile.foo]
sections節to indicate指し示すhow that profile should compile panic support.
New Compiler Flags
The first component
$ rustc -C help
Available codegen options:
...
-C panic=val -- strategy to compile in for panic related code
...
There will currently be two supported strategies:
unwind
- this is what the compiler implements実装するby default today via theinvoke
LLVM instruction.命令abort
- this will implement実装するthat-Z no-landing-pads
does today, which is to disable theinvoke
instruction命令and usecall
instead everywhere.
This codegen option will default to unwind
if not specified
Panic Attributes
Very similarly
#![needs_panic_runtime]
- indicates that this crate requires a "panic runtime" to link correctly. This will be attached to the standard library and is not intended to be attached to any other crate.#![panic_runtime]
- indicates that this crate is a runtime implementation実装of panics.
As with allocators, there are a number of limitations imposed by these attributes by the compiler:
- Any crate DAG can only contain含むat most one instance実例of
#![panic_runtime]
. - Implicit暗黙のdependency依存、依存関係edges are drawn from crates tagged with
#![needs_panic_runtime]
to those tagged with#![panic_runtime]
. Loops as usual are forbidden (e.g. a panic runtime can't depend on libstd). - Complete完全なartifacts which include a crate tagged with
#![needs_panic_runtime]
must include a panic runtime. This includes executables, dylibs, and staticlibs. If no panic runtime is explicitly明示的にlinked, then the compiler will select an appropriate runtime to inject. - Finally, the compiler will ensure保証するthat panic runtimes and compilation modes are not mismatched. For a final product (outputs that aren't rlibs) the
-C panic
mode of the panic runtime must match一致する、マッチさせるthe final product itself. If the panic mode isabort
, then no other validation is performed, but otherwiseさもなければall crates in the DAG must have the same value of-C panic
.
The purpose of these limitations is to solve a number of problems that arise when switching panic strategies. For example with aborting panic crates won't have to link to runtime support of unwinding, or rustc will disallow
The actualextern
symbols known to the crates that need a panic runtime, and that's how they'll communicate/link up.
Panic Crates
Two new unstable crates will be added
panic_unwind
- this is an extraction of the current implementation実装of panicking from the standard library. It will use the same mechanism仕組み、機構of stack unwinding as is implemented実装するon all current platforms.panic_abort
- this is a new implementation実装of panicking which will simply translate unwinding to process aborts. There will be no runtime support required by this crate.
The compiler will assume#![needs_panic_runtime]
).
Compiler defaults
The compiler will ship with a few defaults which affect how panic runtimes are selected in Rust programs. Specifically:
-
The
-C panic
option will default to unwind as it does today. -
The libtest crate will explicitly
明示的にlink topanic_unwind
. The test runner that libtest implements実装するrelies on equating panics with failure and cannot work if panics are translated to aborts. -
If no panic runtime is explicitly
明示的にselected, the compiler will employ the following logic to decide what panic runtime to inject:- If any crate in the DAG is compiled with
-C panic=abort
, thenpanic_abort
will be injected. - If all crates in the DAG are compiled with
-C panic=unwind
, thenpanic_unwind
is injected.
- If any crate in the DAG is compiled with
Cargo changes
In order[profile]
section
[profile.dev]
panic = 'unwind'
This will cause-C panic=unwind
to all rustc
invocationscargo test
it cannot pass -C panic=abort
.
Drawbacks
-
The implementation
実装of custom allocators was no small feat in the compiler, and much of this RFC is essentially the same thing. Similar似ている、同様のinfrastructure can likely be leveraged to alleviate the implementation実装complexity, but this is undeniably a large change to the compiler for albeit a relatively minor option. The counter point to this, however, is that disabling unwinding in a principled fashion provides与えるfar higher quality error messages, prevents防ぐerroneous誤った、間違いのsituations, and provides与えるan immediate benefit for many Rust users today. -
The binary
2進数distribution of the standard library will not change from what it is today. In other words, the standard library (and dependency依存、依存関係crates like libcore) will be compiled with-C panic=unwind
. This introduces the opportunity for extra code bloat or missed optimizations in applications that end up disabling unwinding in the long run. Distribution, however, is far easier because there's only one copy of the standard library and we don't have to rely on any other form形式、形態、形作るof infrastructure. -
This represents
表現するa proliferation of the#![needs_foo]
and#![foo]
style system that allocators have begun. This may be indicative of a deeper underlying裏に潜んだ、背後のrequirement here of the standard library or perhaps showing how the strategy in the standard library needs to change. If the standard library were a crates.io crate it would arguably support these options via Cargo features, but without that option is this the best way to be implementing実装するthese switches for the standard library?
Alternatives
-
Currently this RFC allows
許可する、可能にするmixing multiple複数のpanic runtimes in a crate graph so long as the actual実際のruntime is compiled with-C panic=abort
. This is primarily done to immediately直後に、直接的にreap benefit from-C panic=abort
even though the standard library we distribute will still have unwinding support compiled in (compiled with-C panic=unwind
). In the not-too-distant future however, we will likely be poised to distribute multiple複数のbinary2進数copies of the standard library compiled with different profiles. We may be able to tighten this restriction制限on behalf of the compiler, requiring that all crates in a DAG have the same-C panic
compilation mode, but there would unfortunately be no immediate benefit to implementing実装するthe RFC from users of our precompiled nightlies.This alternative,
代わりのもの、選択肢additionally, can also be viewed as a drawback. It's unclear what a future libstd distribution mechanism仕組み、機構would look like and how this RFC might interact with it. Stabilizing disabling unwinding via a compiler switch or a Cargo profile option may not end up meshing well with the strategy we pursue with shipping multiple複数のstandard libraries. -
Instead of the panic runtime support in this RFC, we could instead just ship two different copies of the standard library where one simply translates panics to abort instead of unwinding. This is unfortunately very difficult for Cargo or the compiler to track, however, to ensure
保証するthat the codegen option of how panics are translated is propagated throughout the rest of the crate graph. Additionally it may be easy to mix up crates of different panic strategies.
Unresolved questions
-
One possible implementation
実装of unwinding is via return-based flags. Much of this RFC is designed設計(する)with the intention of supporting arbitrary任意のunwinding implementations,実装but it's unclear whether it's too heavily biased towards panic is either unwinding or aborting. -
The current implementation
実装of Cargo would mean that a naive implementation実装of the profile option would cause起こすrecompiles betweencargo build
andcargo test
for projects that specify特定する、指定する、規定するpanic = 'abort'
. Is this acceptable? Should Cargo cache both copies of the crate?