Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1794,6 +1794,7 @@ mod prim_ref {}
/// have different sizes.
///
/// ### ABI compatibility
/// [ABI compatibility]: #abi-compatibility
///
/// Generally, when a function is declared with one signature and called via a function pointer with
/// a different signature, the two signatures must be *ABI-compatible* or else calling the function
Expand Down Expand Up @@ -1831,7 +1832,7 @@ mod prim_ref {}
/// - `*const T`, `*mut T`, `&T`, `&mut T`, `Box<T>` (specifically, only `Box<T, Global>`), and
/// `NonNull<T>` are all ABI-compatible with each other for all `T`. They are also ABI-compatible
/// with each other for _different_ `T` if they have the same metadata type (`<T as
/// Pointee>::Metadata`).
/// Pointee>::Metadata`). However, see the [Control Flow Integrity][cfi-docs] docs for caveats.
/// - `usize` is ABI-compatible with the `uN` integer type of the same size, and likewise `isize` is
/// ABI-compatible with the `iN` integer type of the same size.
/// - `char` is ABI-compatible with `u32`.
Expand Down Expand Up @@ -1890,6 +1891,8 @@ mod prim_ref {}
/// Behavior since transmuting `None::<NonZero<i32>>` to `NonZero<i32>` violates the non-zero
/// requirement.
///
/// [cfi-docs]: https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity
///
/// ### Trait implementations
///
/// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic
Expand Down
31 changes: 31 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/sanitizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,37 @@ Cargo build-std feature (i.e., `-Zbuild-std`) when enabling CFI.

See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.

## Divergence from the Rust ABI

There are some caveats to [the ABI-compatibility rules for Rust-to-Rust
calls][rust-abi] due to how the CFI sanitizer is implemented. CFI is a tool
that can be used to validate that dynamic function calls respect the ABI, but
due to its C/C++ origins, it disagrees with the above documented guarantees in
a few ways, see below. As CFI is unstable, the details may change in the
future.

When running the CFI sanitizer, pointer types are only ABI-compatible if the
target type and mutability is the same. This means that `*mut String` and `*mut
i32` are incompatible when using CFI. It also means that `*mut i32` is
incompatible with `*const i32`. The `NonNull<_>` and `Box<_>` pointer types are
currently considered immutable under CFI. For non-primitive target types, CFI
uses the name of the type for its compatibility check.

When not using the `-Zsanitizer-cfi-normalize-integers` flag, the CFI sanitizer
further restricts the rules by considering `usize`/`isize` incompatible with
the `uN`/`iN` integer type of the same size.

Unlike other cases where the function ABI is violated, function calls that
violate the CFI-specific ABI-compatibility rules are not undefined behavior.
They are guaranteed to either function correctly, or to crash the program.

This section only covers cases where CFI disagrees with the ABI-compatibility
rules for Rust-to-Rust calls. It is not meant to be a complete explanation of
how CFI works, and details important for C-to-Rust or Rust-to-C calls are
omitted.

[rust-abi]: https://doc.rust-lang.org/stable/std/primitive.fn.html#abi-compatibility

## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination

```rust
Expand Down
Loading