Skip to content

Commit 713d59a

Browse files
committedApr 12, 2025·
Auto merge of rust-lang#139632 - Darksonn:cfi-fmt, r=<try>
cfi: do not transmute function pointers in formatting code Follow-up to rust-lang#115954. Addresses rust-lang#115199 point 2. Related to rust-lang#128728. Discussion [on the LKML](https://lore.kernel.org/all/20250410115420.366349-1-panikiel@google.com/). cc `@maurer` `@rcvalle` `@RalfJung`
2 parents 1bc5618 + 6c6a39e commit 713d59a

File tree

1 file changed

+30
-23
lines changed
  • library/core/src/fmt

1 file changed

+30
-23
lines changed
 

Diff for: ‎library/core/src/fmt/rt.rs

+30-23
Original file line numberDiff line numberDiff line change
@@ -65,61 +65,73 @@ pub struct Argument<'a> {
6565
ty: ArgumentType<'a>,
6666
}
6767

68-
#[rustc_diagnostic_item = "ArgumentMethods"]
69-
impl Argument<'_> {
70-
#[inline]
71-
const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> {
68+
macro_rules! argument_new {
69+
($t:ty, $x:expr, $f:expr) => {
7270
Argument {
7371
// INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
7472
// a `fn(&T, ...)`, so the invariant is maintained.
7573
ty: ArgumentType::Placeholder {
76-
value: NonNull::from_ref(x).cast(),
77-
// SAFETY: function pointers always have the same layout.
78-
formatter: unsafe { mem::transmute(f) },
74+
value: NonNull::<$t>::from_ref($x).cast(),
75+
#[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
76+
formatter: {
77+
let f: fn(&$t, &mut Formatter<'_>) -> Result = $f;
78+
// SAFETY: This is only called with `value`, which has the right type.
79+
unsafe { mem::transmute(f) }
80+
},
81+
#[cfg(any(sanitize = "cfi", sanitize = "kcfi"))]
82+
formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| {
83+
let func = $f;
84+
// SAFETY: This is the same type as the `value` field.
85+
let r = unsafe { ptr.cast::<$t>().as_ref() };
86+
(func)(r, fmt)
87+
},
7988
_lifetime: PhantomData,
8089
},
8190
}
82-
}
91+
};
92+
}
8393

94+
#[rustc_diagnostic_item = "ArgumentMethods"]
95+
impl Argument<'_> {
8496
#[inline]
8597
pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
86-
Self::new(x, Display::fmt)
98+
argument_new!(T, x, <T as Display>::fmt)
8799
}
88100
#[inline]
89101
pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
90-
Self::new(x, Debug::fmt)
102+
argument_new!(T, x, <T as Debug>::fmt)
91103
}
92104
#[inline]
93105
pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
94-
Self::new(x, |_, _| Ok(()))
106+
argument_new!(T, x, |_: &T, _| Ok(()))
95107
}
96108
#[inline]
97109
pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
98-
Self::new(x, Octal::fmt)
110+
argument_new!(T, x, <T as Octal>::fmt)
99111
}
100112
#[inline]
101113
pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
102-
Self::new(x, LowerHex::fmt)
114+
argument_new!(T, x, <T as LowerHex>::fmt)
103115
}
104116
#[inline]
105117
pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
106-
Self::new(x, UpperHex::fmt)
118+
argument_new!(T, x, <T as UpperHex>::fmt)
107119
}
108120
#[inline]
109121
pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
110-
Self::new(x, Pointer::fmt)
122+
argument_new!(T, x, <T as Pointer>::fmt)
111123
}
112124
#[inline]
113125
pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
114-
Self::new(x, Binary::fmt)
126+
argument_new!(T, x, <T as Binary>::fmt)
115127
}
116128
#[inline]
117129
pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
118-
Self::new(x, LowerExp::fmt)
130+
argument_new!(T, x, <T as LowerExp>::fmt)
119131
}
120132
#[inline]
121133
pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
122-
Self::new(x, UpperExp::fmt)
134+
argument_new!(T, x, <T as UpperExp>::fmt)
123135
}
124136
#[inline]
125137
#[track_caller]
@@ -135,11 +147,6 @@ impl Argument<'_> {
135147
/// # Safety
136148
///
137149
/// This argument must actually be a placeholder argument.
138-
///
139-
// FIXME: Transmuting formatter in new and indirectly branching to/calling
140-
// it here is an explicit CFI violation.
141-
#[allow(inline_no_sanitize)]
142-
#[no_sanitize(cfi, kcfi)]
143150
#[inline]
144151
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
145152
match self.ty {

0 commit comments

Comments
 (0)