-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Tracking Issue for "C-unwind ABI", RFC 2945 #74990
Comments
Hello! I would be interested in helping implement this RFC. 🙋 (cc: @aturon) |
Hey @katie-martin-fastly, that's great news! I'm going to assign you to the issue for now: @rustbot assign @katie-martin-fastly One thing to mention is that most Rust compiler development discussion takes place on the rust-lang zulip, and this project in particular is chatting in That said, in terms of mentoring and getting started, I think the idea is going to be to adapt an existing mechanism that the compiler offers. We have this attribute I can do more mentoring instructions later but, as a starting point, I updated the head post with some of the major goals of the RFC (see the "Implementation notes") section. Also here are some tips to get you started in terms of reading into the rustc code:
|
### Overview This commit begins the implementation work for RFC 2945. For more information, see the rendered RFC [1] and tracking issue [2]. A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`, and `Thiscall` variants, marking whether unwinding across FFI boundaries is acceptable. The cases where each of these variants' `unwind` member is true correspond with the `C-unwind`, `system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings introduced in RFC 2945 [3]. ### Feature Gate and Unstable Book This commit adds a `c_unwind` feature gate for the new ABI strings. Tests for this feature gate are included in `src/test/ui/c-unwind/`, which ensure that this feature gate works correctly for each of the new ABIs. A new language features entry in the unstable book is added as well. ### Further Work To Be Done This commit does not proceed to implement the new unwinding ABIs, and is intentionally scoped specifically to *defining* the ABIs and their feature flag. ### One Note on Test Churn This will lead to some test churn, in re-blessing hash tests, as the deleted comment in `src/librustc_target/spec/abi.rs` mentioned, because we can no longer guarantee the ordering of the `Abi` variants. While this is a downside, this decision was made bearing in mind that RFC 2945 states the following, in the "Other `unwind` Strings" section [3]: > More unwind variants of existing ABI strings may be introduced, > with the same semantics, without an additional RFC. Adding a new variant for each of these cases, rather than specifying a payload for a given ABI, would quickly become untenable, and make working with the `Abi` enum prone to mistakes. This approach encodes the unwinding information *into* a given ABI, to account for the future possibility of other `-unwind` ABI strings. ### Footnotes [1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md [2]: rust-lang#74990 [3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
…945-c-unwind-abi, r=Amanieu Implement RFC 2945: "C-unwind" ABI ## Implement RFC 2945: "C-unwind" ABI This branch implements [RFC 2945]. The tracking issue for this RFC is rust-lang#74990. The feature gate for the issue is `#![feature(c_unwind)]`. This RFC was created as part of the ffi-unwind project group tracked at rust-lang/lang-team#19. ### Changes Further details will be provided in commit messages, but a high-level overview of the changes follows: * A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`, and `Thiscall` variants, marking whether unwinding across FFI boundaries is acceptable. The cases where each of these variants' `unwind` member is true correspond with the `C-unwind`, `system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings introduced in RFC 2945 [3]. * This commit adds a `c_unwind` feature gate for the new ABI strings. Tests for this feature gate are included in `src/test/ui/c-unwind/`, which ensure that this feature gate works correctly for each of the new ABIs. A new language features entry in the unstable book is added as well. * We adjust the `rustc_middle::ty::layout::fn_can_unwind` function, used to compute whether or not a `FnAbi` object represents a function that should be able to unwind when `panic=unwind` is in use. * Changes are also made to `rustc_mir_build::build::should_abort_on_panic` so that the function ABI is used to determind whether it should abort, assuming that the `panic=unwind` strategy is being used, and no explicit unwind attribute was provided. [RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
Stabilise `c_unwind` Fix rust-lang#74990 Fix rust-lang#115285 (that's also where FCP is happening) Marking as draft PR for now due to `compiler_builtins` issues r? ``@Amanieu``
Stabilise `c_unwind` Fix rust-lang#74990 Fix rust-lang#115285 (that's also where FCP is happening) Marking as draft PR for now due to `compiler_builtins` issues r? `@Amanieu`
Begining within Rust 1.81 (rust-lang/rust#74990) Rust will abort when attempting to unwind a panic across an "extern C" boundary. Previously it was technically UB, but it worked and Mockall relied on it. Now, unwinding across such a boundary requires the "extern C-unwind" ABI. Use that ABI in the generated code. However, don't use that ABI when mocking a C variadic function. That doesn't work, due to rust-lang/rust#126836 . Fixes #584
Begining within Rust 1.81 (rust-lang/rust#74990) Rust will abort when attempting to unwind a panic across an "extern C" boundary. Previously it was technically UB, but it worked and Mockall relied on it. Now, unwinding across such a boundary requires the "extern C-unwind" ABI. Use that ABI in the generated code. However, don't use that ABI when mocking a C variadic function. That doesn't work, due to rust-lang/rust#126836 . Fixes #584
### What Fixes for Rust 1.81: 1. Update semver-checks to 0.35.0. 2. Don't use the `extern` function for invoking a contract function when executing tests. ### Why 1. Semver checks is failing to run on the new version of Rust and needs updating. 2. Rust 1.81.0 changed the behavior of panics on `extern "C"` functions, such that panics cannot be caught by [std::panic::catch_unwind](https://doc.rust-lang.org/std/panic/fn.catch_unwind.html). Contracts expose their functions as an `extern` function that defaults to `extern "C"`. The test environment catches panics inside contract functions and resurfaces them as errors by using catch_unwind. The solution used was to make it so that the test environment never calls through the extern function, and instead calls through a non-extern function that does the same work. This seems like the sanest way to take away any dependence / relationship between the test environment and the Rust C-ABI so that any future changes to the C-ABI don't affect the test environment. An alternative solution would be to mark the contract function as `extern "C-unwind"` so that it retained unwind functionality, but that would continue to bind the SDK test environment to behaviour changes in extern fns. In the solution in this change the Abi qualifier `"C"` has been added. When the Abi qualifier is not specified it defaults to `"C"`, but for the sake of being explicit and removing any doubt from a reader it is now specified. The Rust reference confirms that `"C"` is the default: - https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier. More details on this change to Rust 1.81.0 can be found at: - https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#abort-on-uncaught-panics-in-extern-c-functions - rust-lang/rust#74990 Close #1332
… r=Mark-Simulacrum Update `catch_unwind` doc comments for `c_unwind` Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose. Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP. Related: rust-lang#74990, rust-lang#115285, rust-lang/reference#1226
…=Mark-Simulacrum Update `catch_unwind` doc comments for `c_unwind` Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose. Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP. Related: rust-lang#74990, rust-lang#115285, rust-lang/reference#1226
Make destructors on `extern "C"` frames to be executed This would make the example in rust-lang#123231 print "Noisy Drop". I didn't mark this as fixing the issue because the behaviour is yet to be spec'ed. Tracking: - rust-lang#74990
…ulacrum Update `catch_unwind` doc comments for `c_unwind` Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose. Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP. Related: rust-lang/rust#74990, rust-lang/rust#115285, rust-lang/reference#1226
…ulacrum Update `catch_unwind` doc comments for `c_unwind` Updates `catch_unwind` doc comments to indicate that catching a foreign exception _will no longer_ be UB. Instead, there are two possible behaviors, though it is not specified which one an implementation will choose. Nominated for t-lang to confirm that they are okay with making such a promise based on t-opsem FCP, or whether they would like to be included in the FCP. Related: rust-lang/rust#74990, rust-lang/rust#115285, rust-lang/reference#1226
Unwinding across functions with the extern "C" ABI is UB, but previously worked. See: rust-lang/rust#74990 Redo the tests so they don't rely on panics at all, using a reference-counted counter instead. Signed-off-by: Hector Martin <marcan@marcan.st>
Make destructors on `extern "C"` frames to be executed This would make the example in rust-lang#123231 print "Noisy Drop". I didn't mark this as fixing the issue because the behaviour is yet to be spec'ed. Tracking: - rust-lang#74990
Make destructors on `extern "C"` frames to be executed This would make the example in #123231 print "Noisy Drop". I didn't mark this as fixing the issue because the behaviour is yet to be spec'ed. Tracking: - rust-lang/rust#74990
Make destructors on `extern "C"` frames to be executed This would make the example in #123231 print "Noisy Drop". I didn't mark this as fixing the issue because the behaviour is yet to be spec'ed. Tracking: - rust-lang/rust#74990
Each `bindgen` release may upgrade the list of Rust targets. For instance, currently, in their master branch [1], the latest ones are: Nightly => { vectorcall_abi: #124485, ptr_metadata: #81513, layout_for_ptr: #69835, }, Stable_1_77(77) => { offset_of: #106655 }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 }, By default, the highest stable release in their list is used, and users are expected to set one if they need to support older Rust versions (e.g. see [2]). Thus, over time, new Rust features are used by default, and at some point, it is likely that `bindgen` will emit Rust code that requires a Rust version higher than our minimum (or perhaps enabling an unstable feature). Currently, there is no problem because the maximum they have, as seen above, is Rust 1.77.0, and our current minimum is Rust 1.78.0. Therefore, set a Rust target explicitly now to prevent going forward in time too much and thus getting potential build failures at some point. Since we also support a minimum `bindgen` version, and since `bindgen` does not support passing unknown Rust target versions, we need to use the list of our minimum `bindgen` version, rather than the latest. So, since `bindgen` 0.65.1 had this list [3], we need to use Rust 1.68.0: /// Rust stable 1.64 /// * `core_ffi_c` ([Tracking issue](rust-lang/rust#94501)) => Stable_1_64 => 1.64; /// Rust stable 1.68 /// * `abi_efiapi` calling convention ([Tracking issue](rust-lang/rust#65815)) => Stable_1_68 => 1.68; /// Nightly rust /// * `thiscall` calling convention ([Tracking issue](rust-lang/rust#42202)) /// * `vectorcall` calling convention (no tracking issue) /// * `c_unwind` calling convention ([Tracking issue](rust-lang/rust#74990)) => Nightly => nightly; ... /// Latest stable release of Rust pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_68; Thus add the `--rust-target 1.68` parameter. Add a comment as well explaining this. An alternative would be to use the currently running (i.e. actual) `rustc` and `bindgen` versions to pick a "better" Rust target version. However, that would introduce more moving parts depending on the user setup and is also more complex to implement. Cc: Christian Poveda <git@pvdrz.com> Cc: Emilio Cobos Álvarez <emilio@crisal.io> Link: https://github.com/rust-lang/rust-bindgen/blob/21c60f473f4e824d4aa9b2b508056320d474b110/bindgen/features.rs#L97-L105 [1] Link: rust-lang/rust-bindgen#2960 [2] Link: https://github.com/rust-lang/rust-bindgen/blob/7d243056d335fdc4537f7bca73c06d01aae24ddc/bindgen/features.rs#L131-L150 [3] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Each `bindgen` release may upgrade the list of Rust targets. For instance, currently, in their master branch [1], the latest ones are: Nightly => { vectorcall_abi: #124485, ptr_metadata: #81513, layout_for_ptr: #69835, }, Stable_1_77(77) => { offset_of: #106655 }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 }, By default, the highest stable release in their list is used, and users are expected to set one if they need to support older Rust versions (e.g. see [2]). Thus, over time, new Rust features are used by default, and at some point, it is likely that `bindgen` will emit Rust code that requires a Rust version higher than our minimum (or perhaps enabling an unstable feature). Currently, there is no problem because the maximum they have, as seen above, is Rust 1.77.0, and our current minimum is Rust 1.78.0. Therefore, set a Rust target explicitly now to prevent going forward in time too much and thus getting potential build failures at some point. Since we also support a minimum `bindgen` version, and since `bindgen` does not support passing unknown Rust target versions, we need to use the list of our minimum `bindgen` version, rather than the latest. So, since `bindgen` 0.65.1 had this list [3], we need to use Rust 1.68.0: /// Rust stable 1.64 /// * `core_ffi_c` ([Tracking issue](rust-lang/rust#94501)) => Stable_1_64 => 1.64; /// Rust stable 1.68 /// * `abi_efiapi` calling convention ([Tracking issue](rust-lang/rust#65815)) => Stable_1_68 => 1.68; /// Nightly rust /// * `thiscall` calling convention ([Tracking issue](rust-lang/rust#42202)) /// * `vectorcall` calling convention (no tracking issue) /// * `c_unwind` calling convention ([Tracking issue](rust-lang/rust#74990)) => Nightly => nightly; ... /// Latest stable release of Rust pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_68; Thus add the `--rust-target 1.68` parameter. Add a comment as well explaining this. An alternative would be to use the currently running (i.e. actual) `rustc` and `bindgen` versions to pick a "better" Rust target version. However, that would introduce more moving parts depending on the user setup and is also more complex to implement. Cc: Christian Poveda <git@pvdrz.com> Cc: Emilio Cobos Álvarez <emilio@crisal.io> Link: https://github.com/rust-lang/rust-bindgen/blob/21c60f473f4e824d4aa9b2b508056320d474b110/bindgen/features.rs#L97-L105 [1] Link: rust-lang/rust-bindgen#2960 [2] Link: https://github.com/rust-lang/rust-bindgen/blob/7d243056d335fdc4537f7bca73c06d01aae24ddc/bindgen/features.rs#L131-L150 [3] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Each `bindgen` release may upgrade the list of Rust targets. For instance, currently, in their master branch [1], the latest ones are: Nightly => { vectorcall_abi: #124485, ptr_metadata: #81513, layout_for_ptr: #69835, }, Stable_1_77(77) => { offset_of: #106655 }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 }, By default, the highest stable release in their list is used, and users are expected to set one if they need to support older Rust versions (e.g. see [2]). Thus, over time, new Rust features are used by default, and at some point, it is likely that `bindgen` will emit Rust code that requires a Rust version higher than our minimum (or perhaps enabling an unstable feature). Currently, there is no problem because the maximum they have, as seen above, is Rust 1.77.0, and our current minimum is Rust 1.78.0. Therefore, set a Rust target explicitly now to prevent going forward in time too much and thus getting potential build failures at some point. Since we also support a minimum `bindgen` version, and since `bindgen` does not support passing unknown Rust target versions, we need to use the list of our minimum `bindgen` version, rather than the latest. So, since `bindgen` 0.65.1 had this list [3], we need to use Rust 1.68.0: /// Rust stable 1.64 /// * `core_ffi_c` ([Tracking issue](rust-lang/rust#94501)) => Stable_1_64 => 1.64; /// Rust stable 1.68 /// * `abi_efiapi` calling convention ([Tracking issue](rust-lang/rust#65815)) => Stable_1_68 => 1.68; /// Nightly rust /// * `thiscall` calling convention ([Tracking issue](rust-lang/rust#42202)) /// * `vectorcall` calling convention (no tracking issue) /// * `c_unwind` calling convention ([Tracking issue](rust-lang/rust#74990)) => Nightly => nightly; ... /// Latest stable release of Rust pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_68; Thus add the `--rust-target 1.68` parameter. Add a comment as well explaining this. An alternative would be to use the currently running (i.e. actual) `rustc` and `bindgen` versions to pick a "better" Rust target version. However, that would introduce more moving parts depending on the user setup and is also more complex to implement. Starting with `bindgen` 0.71.0 [4], we will be able to set any future Rust version instead, i.e. we will be able to set here our minimum supported Rust version. Christian implemented it [5] after seeing this patch. Thanks! Cc: stable@vger.kernel.org # 6.12.y only (since older LTSs only support a single `bindgen` version) Cc: Christian Poveda <git@pvdrz.com> Cc: Emilio Cobos Álvarez <emilio@crisal.io> Link: https://github.com/rust-lang/rust-bindgen/blob/21c60f473f4e824d4aa9b2b508056320d474b110/bindgen/features.rs#L97-L105 [1] Link: rust-lang/rust-bindgen#2960 [2] Link: https://github.com/rust-lang/rust-bindgen/blob/7d243056d335fdc4537f7bca73c06d01aae24ddc/bindgen/features.rs#L131-L150 [3] Link: https://github.com/rust-lang/rust-bindgen/blob/main/CHANGELOG.md#0710-2024-12-06 [4] Link: rust-lang/rust-bindgen#2993 [5] Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20241123180323.255997-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Each `bindgen` release may upgrade the list of Rust targets. For instance, currently, in their master branch [1], the latest ones are: Nightly => { vectorcall_abi: #124485, ptr_metadata: #81513, layout_for_ptr: #69835, }, Stable_1_77(77) => { offset_of: #106655 }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 }, By default, the highest stable release in their list is used, and users are expected to set one if they need to support older Rust versions (e.g. see [2]). Thus, over time, new Rust features are used by default, and at some point, it is likely that `bindgen` will emit Rust code that requires a Rust version higher than our minimum (or perhaps enabling an unstable feature). Currently, there is no problem because the maximum they have, as seen above, is Rust 1.77.0, and our current minimum is Rust 1.78.0. Therefore, set a Rust target explicitly now to prevent going forward in time too much and thus getting potential build failures at some point. Since we also support a minimum `bindgen` version, and since `bindgen` does not support passing unknown Rust target versions, we need to use the list of our minimum `bindgen` version, rather than the latest. So, since `bindgen` 0.65.1 had this list [3], we need to use Rust 1.68.0: /// Rust stable 1.64 /// * `core_ffi_c` ([Tracking issue](rust-lang/rust#94501)) => Stable_1_64 => 1.64; /// Rust stable 1.68 /// * `abi_efiapi` calling convention ([Tracking issue](rust-lang/rust#65815)) => Stable_1_68 => 1.68; /// Nightly rust /// * `thiscall` calling convention ([Tracking issue](rust-lang/rust#42202)) /// * `vectorcall` calling convention (no tracking issue) /// * `c_unwind` calling convention ([Tracking issue](rust-lang/rust#74990)) => Nightly => nightly; ... /// Latest stable release of Rust pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_68; Thus add the `--rust-target 1.68` parameter. Add a comment as well explaining this. An alternative would be to use the currently running (i.e. actual) `rustc` and `bindgen` versions to pick a "better" Rust target version. However, that would introduce more moving parts depending on the user setup and is also more complex to implement. Starting with `bindgen` 0.71.0 [4], we will be able to set any future Rust version instead, i.e. we will be able to set here our minimum supported Rust version. Christian implemented it [5] after seeing this patch. Thanks! Cc: Christian Poveda <git@pvdrz.com> Cc: Emilio Cobos Álvarez <emilio@crisal.io> Cc: stable@vger.kernel.org # needed for 6.12.y; unneeded for 6.6.y; do not apply to 6.1.y Fixes: c844fa6 ("rust: start supporting several `bindgen` versions") Link: https://github.com/rust-lang/rust-bindgen/blob/21c60f473f4e824d4aa9b2b508056320d474b110/bindgen/features.rs#L97-L105 [1] Link: rust-lang/rust-bindgen#2960 [2] Link: https://github.com/rust-lang/rust-bindgen/blob/7d243056d335fdc4537f7bca73c06d01aae24ddc/bindgen/features.rs#L131-L150 [3] Link: https://github.com/rust-lang/rust-bindgen/blob/main/CHANGELOG.md#0710-2024-12-06 [4] Link: rust-lang/rust-bindgen#2993 [5] Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20241123180323.255997-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This is a tracking issue for the RFC "C-unwind ABI" (rust-lang/rfcs#2945).
The feature gate for the issue is
#![feature(c_unwind)]
.This RFC was created as part of the ffi-unwind project group tracked at rust-lang/lang-team#19.
About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also uses as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
extern "C" fn"
extern "C"
frames to be executed #129582Implementation notes
Major provisions in the RFC:
C-unwind
ABI andsystem-unwind
(I think), we may need more variants.extern "C" fn foo() { ... }
, we want to force them to abort if there is a panic. The MIR helper functionshould_abort_on_panic
already exists and I think will modify the generated code to insert the required shims in such a case. They should also be marked as "nounwind" in LLVM, if they're not already.Unresolved Questions
None. The unresolved questions in the RFC were meant to be solved by future RFCs building on this one.
Implementation history
#[unwind]
, adjusting panic handling): rustc: Fill out remaining parts of C-unwind ABI #86155The text was updated successfully, but these errors were encountered: