You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/behavior-considered-undefined.md
+8-1
Original file line number
Diff line number
Diff line change
@@ -77,7 +77,7 @@ r[undefined.target-feature]
77
77
does not support (see [`target_feature`]), *except* if the platform explicitly documents this to be safe.
78
78
79
79
r[undefined.call]
80
-
* Calling a function with the wrong call ABI or unwinding from a function with the wrong unwind ABI.
80
+
* Calling a function with the wrong [call ABI][abi], or unwinding past a stack frame that does not allow unwinding (e.g. by calling a `"C-unwind"` function imported or transmuted as a `"C"` function or function pointer).
81
81
82
82
r[undefined.invalid]
83
83
* Producing an [invalid value][invalid-values]. "Producing" a
'Reinterpreting' refers to loading the pointer value at integer type without a
97
97
cast, e.g. by doing raw pointer casts or using a union.
98
98
99
+
r[undefined.runtime]
100
+
* Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented.
101
+
* For assumptions specifically related to unwinding, see the [panic documentation][unwinding-ffi].
102
+
* 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`.
103
+
99
104
> **Note**: Undefined behavior affects the entire program. For example, calling
100
105
> a function in C that exhibits undefined behavior of C means your entire
101
106
> program contains undefined behaviour that can also affect the Rust code. And
@@ -245,6 +250,7 @@ reading uninitialized memory is permitted are inside `union`s and in "padding"
Copy file name to clipboardExpand all lines: src/crates-and-source-files.md
+9-4
Original file line number
Diff line number
Diff line change
@@ -122,13 +122,17 @@ use foo::bar as main;
122
122
<!-- If the previous section needs updating (from "must take no arguments"
123
123
onwards, also update it in the testing.md file -->
124
124
125
+
r[crate.uncaught-foreign-unwinding]
126
+
### Uncaught foreign unwinding
127
+
128
+
When a "foreign" unwind (e.g. an exception thrown from C++ code, or a `panic!` in Rust code using a different panic handler) propagates beyond 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`.
129
+
130
+
For more information, see the [panic documentation][panic-docs].
131
+
125
132
r[crate.no_main]
126
133
### The `no_main` attribute
127
134
128
-
129
-
The *`no_main`[attribute]* may be applied at the crate level to disable
130
-
emitting the `main` symbol for an executable binary. This is useful when some
131
-
other object being linked to defines `main`.
135
+
The *`no_main`[attribute]* may be applied at the crate level to disable emitting the `main` symbol for an executable binary. This is useful when some other object being linked to defines `main`.
Copy file name to clipboardExpand all lines: src/destructors.md
+15-1
Original file line number
Diff line number
Diff line change
@@ -274,7 +274,7 @@ Temporaries are also created to hold the result of operands to an expression
274
274
while the other operands are evaluated. The temporaries are associated to the
275
275
scope of the expression with that operand. Since the temporaries are moved from
276
276
once the expression is evaluated, dropping them has no effect unless one of the
277
-
operands to an expression breaks out of the expression, returns, or panics.
277
+
operands to an expression breaks out of the expression, returns, or [panics][panic].
278
278
279
279
```rust
280
280
# structPrintOnDrop(&'staticstr);
@@ -425,6 +425,8 @@ let x = (&temp()).use_temp(); // ERROR
425
425
r[destructors.forget]
426
426
## Not running destructors
427
427
428
+
r[destructors.manually-suppressing]
429
+
### Manually suppressing destructors
428
430
429
431
[`std::mem::forget`] can be used to prevent the destructor of a variable from being run,
430
432
and [`std::mem::ManuallyDrop`] provides a wrapper to prevent a
@@ -433,6 +435,15 @@ variable or field from being dropped automatically.
433
435
> Note: Preventing a destructor from being run via [`std::mem::forget`] or other means is safe even if it has a type that isn't `'static`.
434
436
> Besides the places where destructors are guaranteed to run as defined by this document, types may *not* safely rely on a destructor being run for soundness.
435
437
438
+
r[destructors.process-termination]
439
+
### Process termination without unwinding
440
+
441
+
There are some ways to terminate the process without [unwinding], in which case destructors will not be run.
442
+
443
+
The standard library provides [`std::process::exit`] and [`std::process::abort`] to do this explicitly. Additionally, if the [panic handler][panic.panic_handler.std] is set to `abort`, panicking will always terminate the process without destructors being run.
444
+
445
+
There is one additional case to be aware of: when a panic reaches a [non-unwinding ABI boundary], either no destructors will run, or all destructors up until the ABI boundary will run.
Copy file name to clipboardExpand all lines: src/items/external-blocks.md
+23-9
Original file line number
Diff line number
Diff line change
@@ -106,8 +106,7 @@ unsafe extern "stdcall" { }
106
106
```
107
107
108
108
r[items.extern.abi.standard]
109
-
There are three ABI strings which are cross-platform, and which all compilers
110
-
are guaranteed to support:
109
+
The following ABI strings are supported on all platforms:
111
110
112
111
r[items.extern.abi.rust]
113
112
*`unsafe extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
@@ -122,6 +121,9 @@ r[items.extern.abi.system]
122
121
which case it's `"stdcall"`, or what you should use to link to the Windows
123
122
API itself
124
123
124
+
r[items.extern.abi.unwind]
125
+
*`extern "C-unwind"` and `extern "system-unwind"` -- identical to `"C"` and `"system"`, respectively, but with [different behavior][unwind-behavior] when the callee unwinds (by panicking or throwing a C++ style exception).
126
+
125
127
r[items.extern.abi.platform]
126
128
There are also some platform-specific ABI strings:
127
129
@@ -151,6 +153,17 @@ r[items.extern.abi.thiscall]
151
153
r[items.extern.abi.efiapi]
152
154
*`unsafe extern "efiapi"` -- The ABI used for [UEFI] functions.
153
155
156
+
r[items.extern.abi.platform-unwind-variants]
157
+
Like `"C"` and `"system"`, most platform-specific ABI strings also have a [corresponding `-unwind` variant][unwind-behavior]; specifically, these are:
158
+
159
+
*`"aapcs-unwind"`
160
+
*`"cdecl-unwind"`
161
+
*`"fastcall-unwind"`
162
+
*`"stdcall-unwind"`
163
+
*`"sysv64-unwind"`
164
+
*`"thiscall-unwind"`
165
+
*`"win64-unwind"`
166
+
154
167
r[items.extern.variadic]
155
168
## Variadic functions
156
169
@@ -428,10 +441,9 @@ Attributes on extern function parameters follow the same rules and
Functions with an ABI that differs from `"Rust"` do not support unwinding in the
258
-
exact same way that Rust does. Therefore, unwinding past the end of functions
259
-
with such ABIs causes the process to abort.
257
+
### Unwinding
260
258
261
-
> **Note**: The LLVM backend of the `rustc` implementation
262
-
aborts the process by executing an illegal instruction.
259
+
r[items.fn.extern.unwind.intro]
260
+
Most ABI strings come in two variants, one with an `-unwind` suffix and one without. The `Rust` ABI always permits unwinding, so there is no `Rust-unwind` ABI. The choice of ABI, together with the runtime [panic handler], determines the behavior when unwinding out of a function.
261
+
262
+
r[items.fn.extern.unwind.behavior]
263
+
The table below indicates the behavior of an unwinding operation reaching each type of ABI boundary (function declaration or definition using the corresponding ABI string). Note that the Rust runtime is not affected by, and cannot have an effect on, any unwinding that occurs entirely within another language's runtime, that is, unwinds that are thrown and caught without reaching a Rust ABI boundary.
264
+
265
+
The `panic`-unwind column refers to [panicking] via the `panic!` macro and similar standard library mechanisms, as well as to any other Rust operations that cause a panic, such as out-of-bounds array indexing or integer overflow.
266
+
267
+
The "unwinding" ABI category refers to `"Rust"` (the implicit ABI of Rust functions not marked `extern`), `"C-unwind"`, and any other ABI with `-unwind` in its name. The "non-unwinding" ABI category refers to all other ABI strings, including `"C"` and `"stdcall"`.
268
+
269
+
Native unwinding is defined per-target. On targets that support throwing and catching C++ exceptions, it refers to the mechanism used to implement this feature. Some platforms implement a form of unwinding referred to as ["forced unwinding"][forced-unwinding]; `longjmp` on Windows and `pthread_exit` in `glibc` are implemented this way. Forced unwinding is explicitly excluded from the "Native unwind" column in the table.
|`panic=unwind`| non-unwinding | abort (see notes below) |[undefined behavior]|
275
+
|`panic=abort`| unwinding |`panic` aborts without unwinding | abort |
276
+
|`panic=abort`| non-unwinding |`panic` aborts without unwinding |[undefined behavior]|
277
+
278
+
r[items.fn.extern.abort]
279
+
With `panic=unwind`, when a `panic` is turned into an abort by a non-unwinding ABI boundary, either no destructors (`Drop` calls) will run, or all destructors up until the ABI boundary will run. It is unspecified which of those two behaviors will happen.
280
+
281
+
For other considerations and limitations regarding unwinding across FFI boundaries, see the [relevant section in the Panic documentation][panic-ffi].
Functions qualified with the `const` keyword are [const functions], as are
269
-
[tuple struct] and [tuple variant] constructors. _Const functions_ can be
270
-
called from within [const contexts].
293
+
Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be called from within [const contexts].
271
294
272
295
r[items.fn.const.extern]
273
296
Const functions may use the [`extern`] function qualifier.
If you are mixing Rust with foreign code (e.g. C, C++) and wish to make a single
257
260
binary containing both types of code, you have two approaches for the final
258
261
binary link:
@@ -268,6 +271,36 @@ binary link:
268
271
269
272
Passing `rlib`s directly into your foreign linker is currently unsupported.
270
273
274
+
> [!NOTE]
275
+
> Rust code compiled or linked with a different instance of the Rust runtime counts as "foreign code" for the purpose of this section.
276
+
277
+
r[link.unwinding]
278
+
### Prohibited linkage and unwinding
279
+
280
+
r[link.unwinding.intro]
281
+
Panic unwinding can only be used if the binary is built consistently according to the following rules.
282
+
283
+
r[link.unwinding.potential]
284
+
A Rust artifact is called *potentially unwinding* if any of the following conditions is met:
285
+
- The artifact uses the [`unwind` panic handler][panic.panic_handler].
286
+
- The artifact contains a crate built with the `unwind`[panic strategy] that makes a call to a function using a `-unwind` ABI.
287
+
- The artifact makes a `"Rust"` ABI call to code running in another Rust artifact that has a separate copy of the Rust runtime, and that other artifact is potentially unwinding.
288
+
289
+
> [!NOTE]
290
+
> This definition captures whether a `"Rust"` ABI call inside a Rust artifact can ever unwind.
291
+
292
+
r[link.unwinding.prohibited]
293
+
If a Rust artifact is potentially unwinding, then all its crates must be built with the `unwind`[panic strategy]. Otherwise, unwinding can cause undefined behavior.
294
+
295
+
> [!NOTE]
296
+
> If you are using `rustc` to link, these rules are enforced automatically. If you are *not* using `rustc` to link, you must take care to ensure that unwinding is handled consistently across the entire binary. Linking without `rustc` includes using `dlopen` or similar facilities where linking is done by the system runtime without `rustc` being involved. This can only happen when mixing code with different [`-C panic`] flags, so most users do not have to be concerned about this.
297
+
298
+
> [!NOTE]
299
+
> To guarantee that a library will be sound (and linkable with `rustc`) regardless of the panic runtime used at link-time, the [`ffi_unwind_calls` lint] may be used. The lint flags any calls to `-unwind` foreign functions or function pointers.
0 commit comments