about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlice Ryhl <aliceryhl@google.com>2025-04-14 06:52:32 +0000
committerAlice Ryhl <aliceryhl@google.com>2025-04-15 07:25:42 +0000
commit6513df96525704d3c40f16faf2672adaaa3186ac (patch)
tree9591c0e8977f18ec8190a691cd0a3286c9d899b2
parent1cbdfab75d6dbf9c383ece8fe2e2642e5db2f2e7 (diff)
downloadrust-6513df96525704d3c40f16faf2672adaaa3186ac.tar.gz
rust-6513df96525704d3c40f16faf2672adaaa3186ac.zip
Add comment
Co-authored-by: Ralf Jung <post@ralfj.de>
-rw-r--r--library/core/src/fmt/rt.rs19
1 files changed, 19 insertions, 0 deletions
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index b9cae8645cd..adcfdd309b7 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -72,6 +72,25 @@ macro_rules! argument_new {
             // a `fn(&T, ...)`, so the invariant is maintained.
             ty: ArgumentType::Placeholder {
                 value: NonNull::<$t>::from_ref($x).cast(),
+                // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to
+                // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed.
+                // However, the CFI sanitizer does not allow this, and triggers a crash when it
+                // happens.
+                //
+                // To avoid this crash, we use a helper function when CFI is enabled. To avoid the
+                // cost of this helper function (mainly code-size) when it is not needed, we
+                // transmute the function pointer otherwise.
+                //
+                // This is similar to what the Rust compiler does internally with vtables when KCFI
+                // is enabled, where it generates trampoline functions that only serve to adjust the
+                // expected type of the argument. `ArgumentType::Placeholder` is a bit like a
+                // manually constructed trait object, so it is not surprising that the same approach
+                // has to be applied here as well.
+                //
+                // It is still considered problematic (from the Rust side) that CFI rejects entirely
+                // legal Rust programs, so we do not consider anything done here a stable guarantee,
+                // but meanwhile we carry this work-around to keep Rust compatible with CFI and
+                // KCFI.
                 #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
                 formatter: {
                     let f: fn(&$t, &mut Formatter<'_>) -> Result = $f;