From 6b624fe6f5a1662d4ecdb9cab82c0443ead6304b Mon Sep 17 00:00:00 2001 From: Kyle J Strand Date: Sat, 31 Aug 2024 14:08:57 -0600 Subject: [PATCH] new guarantee regarding drops before abort; document what happens when foreign unwind causes process termination --- src/behavior-considered-undefined.md | 4 ++-- src/crates-and-source-files.md | 12 ++++++++++++ src/items/functions.md | 10 +++++++++- src/panic.md | 13 +++++++------ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index f310acdd8..7b3a72a8a 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -75,7 +75,7 @@ Please read the [Rustonomicon] before writing unsafe code. * Violating assumptions of the Rust runtime. This is only possible using mechanisms outside Rust. Most assumptions of the Rust runtime are currently not explicitly documented. - * For assumptions specifically related to unwinding, see [unwinding-ub]. + * For assumptions specifically related to unwinding, see [unwinding-ffi]. * The runtime assumes that a Rust stack frame is not deallocated without executing destructors for local variables owned by the stack frame. This assumption can be violated by C functions like `longjmp`. @@ -196,5 +196,5 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" [project-field]: expressions/field-expr.md [project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions [project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions -[unwinding-ub]: panic.md#unwinding-ub +[unwinding-ffi]: panic.md#unwinding-ffi [const-promoted]: destructors.md#constant-promotion diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 426ee26f1..c238a2dd2 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -103,6 +103,17 @@ use foo::bar as main; +### Uncaught foreign unwinding + +When a "foreign" unwind (e.g. an exception thrown from C++ code, or a `panic!` +in Rust code compiled or linked with a different runtime) is not caught before +reaching the `main` function, the process will be safely terminated. This may +take the form of an abort, in which case it is not guaranteed that any `Drop` +calls will be executed, and the error output may be less informative than if the +runtime had been terminated by a "native" Rust `panic`. + +For more information, see the [panic documentation][panic-docs]. + ### The `no_main` attribute The *`no_main` [attribute]* may be applied at the crate level to disable @@ -142,6 +153,7 @@ or `_` (U+005F) characters. [function]: items/functions.md [module]: items/modules.md [module path]: paths.md +[panic-docs]: panic.md#unwinding-ffi [shebang]: input-format.md#shebang-removal [trait or lifetime bounds]: trait-bounds.md [where clauses]: items/generics.md#where-clauses diff --git a/src/items/functions.md b/src/items/functions.md index 24c9c8b59..465d7ccc3 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -244,12 +244,20 @@ from the "Native unwind" column in the table. | panic runtime | ABI | `panic`-unwind | Native unwind (unforced) | | -------------- | ------------ | ------------------------------------- | ----------------------- | | `panic=unwind` | unwinding | unwind | unwind | -| `panic=unwind` | non-unwinding | abort | [undefined behavior] | +| `panic=unwind` | non-unwinding | abort[^1] | [undefined behavior] | | `panic=abort` | unwinding | `panic!` aborts (no unwinding occurs) | abort | | `panic=abort` | non-unwinding | `panic!` aborts (no unwinding occurs) | [undefined behavior] | +[^1]: In this case, either no destructors (`Drop` calls) will run, or all + destructors up until the `extern "C"` boundary (or other such "no unwind" + boundary) will run. + +For other considerations and limitations regarding unwinding across FFI +boundaries, see the [relevant section in the Panic documentation][panic-ffi]. + [forced-unwinding]: https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html#forced-unwinding [panic-modes]: ../panic.md#panic-runtimes +[panic-ffi]: ../panic.md#unwind-ffi [undefined behavior]: ../behavior-considered-undefined.md ## Const functions diff --git a/src/panic.md b/src/panic.md index 6401b3482..8eebe4ef1 100644 --- a/src/panic.md +++ b/src/panic.md @@ -40,13 +40,14 @@ just as if they had gone out of scope normally. > continue running). ### Unwinding across FFI boundaries -[unwinding-ub]: #unwinding-across-ffi-boundaries +[unwinding-ffi]: #unwinding-across-ffi-boundaries -It is possible to unwind across FFI boundaries; this creates unique -opportunities for undefined behavior, especially when multiple language -runtimes are involved. +It is possible to unwind across FFI boundaries using an [appropriate ABI +declaration][unwind-abi]. While useful in certain cases, this creates unique +opportunities for undefined behavior, especially when multiple language runtimes +are involved. -Unwinding with the wrong [ABI][abi] is undefined behavior: +Unwinding with the wrong ABI is undefined behavior: * Causing an unwind into Rust code from a foreign function that was called via a function declaration or pointer declared with a non-unwinding ABI, such as `"C"`, @@ -92,10 +93,10 @@ impossible, which can result in both code-size and runtime speed improvements. See also the [`panic_handler` attribute](runtime.md#the-panic_handler-attribute) which can be used to change the behavior of panics. -[abi]: abi.md [array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions [destructors]: destructors.md [fn-catch-unwind]: ../std/panic/fn.catch_unwind.html [macro-panic]: ../std/macro.panic.html [runtime]: runtime.md [thread-spawn]: ../std/thread/fn.spawn.html +[unwind-abi]: items/functions.md#unwinding \ No newline at end of file