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

panic runtime and C-unwind documentation #1226

Open
wants to merge 36 commits into
base: master
Choose a base branch
from

Conversation

BatmanAoD
Copy link
Member

@BatmanAoD BatmanAoD commented May 29, 2022

Tracking issue: rust-lang/rust#74990

Closes #579

@BatmanAoD BatmanAoD marked this pull request as ready for review May 30, 2022 17:35
@BatmanAoD
Copy link
Member Author

BatmanAoD commented May 30, 2022

Hm... not sure how to fix the links to the newly-introduced page. Is there an index page I need to edit?

Edit: I think I found it

@ehuss ehuss added the S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository label Jun 22, 2022
src/items/functions.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
src/behavior-considered-undefined.md Outdated Show resolved Hide resolved
Comment on lines 219 to 224
| panic runtime | ABI | `panic`-unwind | Unforced foreign unwind |
| -------------- | ------------ | ------------------------------------- | ----------------------- |
| `panic=unwind` | `"C-unwind"` | unwind | unwind |
| `panic=unwind` | `"C"` | abort | UB |
| `panic=abort` | `"C-unwind"` | `panic!` aborts | abort |
| `panic=abort` | `"C"` | `panic!` aborts (no unwinding occurs) | UB |
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
| panic runtime | ABI | `panic`-unwind | Unforced foreign unwind |
| -------------- | ------------ | ------------------------------------- | ----------------------- |
| `panic=unwind` | `"C-unwind"` | unwind | unwind |
| `panic=unwind` | `"C"` | abort | UB |
| `panic=abort` | `"C-unwind"` | `panic!` aborts | abort |
| `panic=abort` | `"C"` | `panic!` aborts (no unwinding occurs) | UB |
| panic runtime | ABI | `panic`-unwind | Unforced foreign unwind |
| -------------- | ------------ | ------------------------------------- | ----------------------- |
| `panic=unwind` | `"C-unwind"` | unwind | unwind |
| `panic=unwind` | `"C"` | abort if unwinding reaches the function | UB if unwinding reaches the function |
| `panic=abort` | `"C-unwind"` | aborts immediately (no unwinding occurs) | abort if unwinding reaches the function |
| `panic=abort` | `"C"` | aborts immediately (no unwinding occurs) | UB if unwinding reaches the function |

I found this a bit confusing. I believe there are subtle differences in terms of where the aborts occur and so forth. I have tried to clarify above, but I think it may be worth further clarifying.

It may also be worth adding some (perhaps non-normative) discussion of implementation:

  • When compiling a function F with panic=unwind and extern "C", the compiler inserts unwinding guards for Rust panics that trigger an abort when unwinding reaches F.

I am also be misunderstanding what's going on. I was a bit surprised to see "UB" for unforced-foreign-unwind with C=unwind. I guess that this table is combining two scenarios:

  • what happens when you call a C++ function declared as extern "C", and it unwinds (UB, we haven't compiled any guards)
  • what happens when an extern "C" Rust function invokes some C++ function that throws (probably, in practice, an abort, but perhaps we have simplified to call it UB?)

Is that right?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's only UB for a foreign function declared as extern "C" to unwind.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nbdd0121 what happens when an extern "C" Rust function unwinds? I believe we insert an abort guard, but this table doesn't clarify that, right? Or maybe I don't understand what it's trying to convey. I'm imagining a scenario like

extern "C-unwind" fn throws();

extern "C" fn rust_fn() {
    throws(); // unwinds
}

In this case, I presume you get an abort -- and I think we guarantee that? But the way I read this table, it would be listed as UB.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm....I don't know if the panic abort guard would currently catch and abort in that case, or if it relies on the personality function to only abort on true Rust panics. I agree that the behavior in the table as-written is UB.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nbdd0121 what happens when an extern "C" Rust function unwinds? I believe we insert an abort guard, but this table doesn't clarify that, right? Or maybe I don't understand what it's trying to convey. I'm imagining a scenario like

extern "C-unwind" fn throws();

extern "C" fn rust_fn() {
    throws(); // unwinds
}

In this case, I presume you get an abort -- and I think we guarantee that? But the way I read this table, it would be listed as UB.

Unwinding out from extern "C" functions (defined in either Rust or foreign language) is UB.
In the case you listed, we insert guard to prevent unwinding from actually leaving a Rust extern "C" functions, therefore the function does not unwind, so UB is prevented; in this case we never unwinds out from a extern "C" Rust functions.

If you define a extern "C-unwind" Rust function and transmute it to extern "C" and then call it, it's not UB if unwinding does not happen, and it's UB if unwinding happens.

Copy link
Member Author

Choose a reason for hiding this comment

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

@nikomatsakis With the change to the verbiage above, explaining that the table entries are specifically describing behavior at function boundaries, do you still want to make a change here?

Copy link

Choose a reason for hiding this comment

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

Please check whether the notes I suggested to add under the table are correct.

Copy link
Member Author

Choose a reason for hiding this comment

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

@nikomatsakis Can I resolve this comment thread now?

src/linkage.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
@BatmanAoD
Copy link
Member Author

Sorry for the delay; I think I've addressed all comments.

@BatmanAoD
Copy link
Member Author

@tmandry @nikomatsakis I'm not sure you saw my comments & changes last week, but I think this is ready for re-review.

@nbdd0121
Copy link
Contributor

Could you squash the commits?

@BatmanAoD
Copy link
Member Author

@nbdd0121 Can that be done on merge? I've heard that GitHub sometimes has trouble with PR branches that receive force-pushes.

src/linkage.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/panic.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
@BatmanAoD
Copy link
Member Author

I think I've resolved all open questions and concerns. Is there anything else needed from me at the moment?

@nbdd0121
Copy link
Contributor

This really needs rebasing now.

@BatmanAoD BatmanAoD force-pushed the c-unwind-documentation branch from e8c62b4 to 6e83797 Compare August 26, 2023 18:49
@BatmanAoD
Copy link
Member Author

@nbdd0121 Done!

@BatmanAoD
Copy link
Member Author

@tmandry two changes since your review:

  • I added the new ABIs to items/external-blocks
  • I added that catching an exception or unwind from the "wrong" language is UB

@BatmanAoD
Copy link
Member Author

@tmandry @ehuss can this be merged, since the partial stabilization was a while ago now?

src/items/external-blocks.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
src/items/functions.md Outdated Show resolved Hide resolved
ehuss added 15 commits January 14, 2025 09:33
We don't document rustc lints as language rules. I think in this case,
it's fine to mention it, but it should just be in a note block.
I believe this is what was intended.
This should probably be reworked in the future so the ABI chapter owns
this information. But for now, it doesn't really say anything useful.
This is to make it clear that the unwind is going *past* it, not just
into it.
We generally don't document old behavior in the reference.
This is intended since there are multiple ways to suppress a destructor.
Per the style guide, lines should not be wrapped.
@ehuss ehuss force-pushed the c-unwind-documentation branch from 4e05720 to c63cdbc Compare January 14, 2025 17:37
ehuss added 5 commits January 14, 2025 09:43
The intent here is to introduce higher-level concepts first, and then go
into the details of unwinding.
This is intended to clearly define two concepts, the runtime versus the
strategy. Although there is significant overlap between them (they are
chosen using the same CLI flag after all), I think it is helpful to
define them as separate concepts.
I felt like this sentence is making an over-bold statement. There are
ways to violate the assumptions of the Rust runtime using Rust code.
Usually that is only with `unsafe` code that is otherwise violating
requirements, though there may still be some holes where it can be done
in safe code (hopefully those holes continue to be plugged). I feel more
comfortable without this, since the primary sentence (don't violate the
runtime!) is enough on its own.
src/linkage.md Outdated Show resolved Hide resolved
src/panic.md Outdated
> The panic runtime can be chosen in `rustc` with the [`-C panic`] CLI flag when building any crate type except an rlib.

> [!NOTE]
> When compiling code that is guaranteed to be linked to a non-recoverable panic runtime, the optimizer may assume that unwinding across Rust frames is impossible, which can result in both code-size and runtime speed improvements.
Copy link
Member

Choose a reason for hiding this comment

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

Isn't it more accurate to say that this is done based on the panic strategy? We do this within a crate when we see -Cpanic=abort, without knowing which runtime will be linked into the final atifact.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. I had made that change in an earlier edit, but backed it out for reasons I don't remember. I agree that it makes sense to frame it that way. Thanks!

src/panic.md Outdated
The actual behavior and implementation of a panic is controlled by the _panic runtime_. The panic runtime is a handler linked into the output which provides the necessary implementation for panicking.

> [!NOTE]
> The Rust standard library provides two panic runtimes: `panic_unwind` (which unwinds the stack and is potentially recoverable) and `panic_abort` (which aborts the process and is non-recoverable). The default runtime depends on the target platform, but is generally `panic_unwind` on platforms with native support for C++ exceptions.
Copy link
Member

Choose a reason for hiding this comment

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

Other parts of the reference normatively refer to the unwind runtime. So I feel like the list of available runtimes is normative, and not just a note?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's a good question, and I was uncertain why it was written that way.

In theory you can provide your own runtime, but I think that requires unstable things (possibly permanently?). I was uncertain if the original here was written with the intent that there could be any number of runtimes based on what the user provides.

There's also this awkward blurred line between the language (the reference), the compiler, and the standard library. Since the panic runtime is provided by the standard library, in theory it could introduce new runtimes that just plug in without needing any updates to "the language".

However, I agree that it would be best to clearly define the two kinds we have now, so I have updated the text to make this normative. If in the future this is more extensible, or we add new runtimes, I think we can revisit how it is worded (if it needs to be more generic).

src/panic.md Outdated
> The panic strategy can be chosen in `rustc` with the [`-C panic`] CLI flag.

r[panic.strategy.mixed]
When linking with the `unwind` runtime, all crates must be built with the `unwind` strategy.
Copy link
Member

Choose a reason for hiding this comment

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

This is redundant with link.unwinding.prohibited.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah! So this goes back to my earlier question/statement about being confused about how this is written.

The introduction (linking.unwinding.intro) is talking about not using rustc. Then it continues into several other rules, but it is not clear if those are a continuation of "what is required when not using rustc".

(To read that in a different way, I could say that these rules don't apply when using rustc since the section repeatedly talks about this being relevant to non-rustc linkers.)

But that, and the note in link.unwinding.prohibited that says you can only violate that with a non-rustc linker makes it confusing to me about those two concepts (A. you cannot mix unwind, B. rustc validates this and generates an error, but normal linkers do not, so be careful!).

Would it be OK if I reword linking.unwinding.intro so that the introduction is a little more generic. Then, move the "if you are not using rustc" stuff to the note in link.unwinding.prohibited? That flow would have less confusion for me.

Copy link
Member

@RalfJung RalfJung Jan 16, 2025

Choose a reason for hiding this comment

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

(To read that in a different way, I could say that these rules don't apply when using rustc since the section repeatedly talks about this being relevant to non-rustc linkers.)

That is basically correct; if you use rustc it will check those rules so you don't have to worry about them.

But yeah I am open to rewording this, I can see how it can be confusing.

ehuss and others added 5 commits January 16, 2025 09:14
At least as it is today, rustc doesn't look at the runtime, but instead
the strategy (`-Cpanic`) of the current crate to elide landing pads and
such when generating object code.
We specifically talk about `abort` and `unwind` already. Let's just go
ahead and up-front define that there are two, and not be so hand-wavey
about it.

In theory the standard library could introduce additional runtimes, and
it doesn't have a specific impact on the language per se. However, this
is a blurred line where I think it is better to be clear about what
there is. We can always revisit this later and adjust if things change.
This reworks this section to change the emphasis on "using non-rustc
linkers". To me, that seemed confusing, since this also applies to using
rustc (just that rustc automatically validates and generates an error if
it is validated).
src/linkage.md Outdated Show resolved Hide resolved
src/linkage.md Show resolved Hide resolved
src/linkage.md Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-lang-nominated S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve panic documentation.