Skip to content

Commit 26c11d6

Browse files
Rollup merge of rust-lang#155361 - Darksonn:abi-cfi, r=RalfJung
Document that CFI diverges from Rust wrt. ABI-compatibility rules The CFI sanitizer is a sanitizer that checks that no ABI-incompatible function calls are made at runtime, but there is currently an unfortunate divergence between the Rust ABI-compatibility rules and what the CFI sanitizer checks. Thus, document that this divergence exists. There are proposals for how we can align the ABI rules to eliminate this discrepancy, and I would like to follow through with those, but for now I think we can at least document that the discrepancy exists. For further discussion please see [Re-evaluate ABI compatibility rules in light of CFI](rust-lang/unsafe-code-guidelines#489) and [Can CFI be made compatible with type erasure schemes?](rust-lang#128728) and [`fn_cast!` macro](rust-lang#140803). cc @rcvalle @samitolvanen @maurer @bjorn3 @RalfJung Rendered: <img width="956" height="391" alt="image" src="https://github.com/user-attachments/assets/410d3eaa-9476-4800-9ef8-bbb100a100c5" />
2 parents 4a06828 + aef93ca commit 26c11d6

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

library/core/src/primitive_docs.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,7 @@ mod prim_ref {}
17941794
/// have different sizes.
17951795
///
17961796
/// ### ABI compatibility
1797+
/// [ABI compatibility]: #abi-compatibility
17971798
///
17981799
/// Generally, when a function is declared with one signature and called via a function pointer with
17991800
/// a different signature, the two signatures must be *ABI-compatible* or else calling the function
@@ -1831,7 +1832,7 @@ mod prim_ref {}
18311832
/// - `*const T`, `*mut T`, `&T`, `&mut T`, `Box<T>` (specifically, only `Box<T, Global>`), and
18321833
/// `NonNull<T>` are all ABI-compatible with each other for all `T`. They are also ABI-compatible
18331834
/// with each other for _different_ `T` if they have the same metadata type (`<T as
1834-
/// Pointee>::Metadata`).
1835+
/// Pointee>::Metadata`). However, see the [Control Flow Integrity][cfi-docs] docs for caveats.
18351836
/// - `usize` is ABI-compatible with the `uN` integer type of the same size, and likewise `isize` is
18361837
/// ABI-compatible with the `iN` integer type of the same size.
18371838
/// - `char` is ABI-compatible with `u32`.
@@ -1890,6 +1891,8 @@ mod prim_ref {}
18901891
/// Behavior since transmuting `None::<NonZero<i32>>` to `NonZero<i32>` violates the non-zero
18911892
/// requirement.
18921893
///
1894+
/// [cfi-docs]: https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity
1895+
///
18931896
/// ### Trait implementations
18941897
///
18951898
/// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic

src/doc/unstable-book/src/compiler-flags/sanitizer.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,37 @@ Cargo build-std feature (i.e., `-Zbuild-std`) when enabling CFI.
246246
247247
See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
248248
249+
## Divergence from the Rust ABI
250+
251+
There are some caveats to [the ABI-compatibility rules for Rust-to-Rust
252+
calls][rust-abi] due to how the CFI sanitizer is implemented. CFI is a tool
253+
that can be used to validate that dynamic function calls respect the ABI, but
254+
due to its C/C++ origins, it disagrees with the above documented guarantees in
255+
a few ways, see below. As CFI is unstable, the details may change in the
256+
future.
257+
258+
When running the CFI sanitizer, pointer types are only ABI-compatible if the
259+
target type and mutability is the same. This means that `*mut String` and `*mut
260+
i32` are incompatible when using CFI. It also means that `*mut i32` is
261+
incompatible with `*const i32`. The `NonNull<_>` and `Box<_>` pointer types are
262+
currently considered immutable under CFI. For non-primitive target types, CFI
263+
uses the name of the type for its compatibility check.
264+
265+
When not using the `-Zsanitizer-cfi-normalize-integers` flag, the CFI sanitizer
266+
further restricts the rules by considering `usize`/`isize` incompatible with
267+
the `uN`/`iN` integer type of the same size.
268+
269+
Unlike other cases where the function ABI is violated, function calls that
270+
violate the CFI-specific ABI-compatibility rules are not undefined behavior.
271+
They are guaranteed to either function correctly, or to crash the program.
272+
273+
This section only covers cases where CFI disagrees with the ABI-compatibility
274+
rules for Rust-to-Rust calls. It is not meant to be a complete explanation of
275+
how CFI works, and details important for C-to-Rust or Rust-to-C calls are
276+
omitted.
277+
278+
[rust-abi]: https://doc.rust-lang.org/stable/std/primitive.fn.html#abi-compatibility
279+
249280
## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination
250281
251282
```rust

0 commit comments

Comments
 (0)