mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-07 17:18:32 +03:00
Document that CFI diverges from Rust wrt. ABI-compatibility rules
This commit is contained in:
@@ -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
|
||||
@@ -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`.
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user