Skip to content

Commit 3fae1c3

Browse files
committed
cfi: do not transmute function pointers in formatting code
1 parent 9054e9d commit 3fae1c3

File tree

2 files changed

+24
-23
lines changed

2 files changed

+24
-23
lines changed

Diff for: core/src/fmt/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8};
77
use crate::marker::PhantomData;
88
use crate::num::fmt as numfmt;
99
use crate::ops::Deref;
10-
use crate::{iter, mem, result, str};
10+
use crate::{iter, result, str};
1111

1212
mod builders;
1313
#[cfg(not(no_fp_fmt_parse))]

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

+23-22
Original file line numberDiff line numberDiff line change
@@ -65,61 +65,67 @@ 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(),
74+
value: NonNull::<$t>::from_ref($x).cast(),
7775
// SAFETY: function pointers always have the same layout.
78-
formatter: unsafe { mem::transmute(f) },
76+
formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| {
77+
let func = $f;
78+
// SAFETY: This is the same type as the `value` field.
79+
let r = unsafe { ptr.cast::<$t>().as_ref() };
80+
(func)(r, fmt)
81+
},
7982
_lifetime: PhantomData,
8083
},
8184
}
82-
}
85+
};
86+
}
8387

88+
#[rustc_diagnostic_item = "ArgumentMethods"]
89+
impl Argument<'_> {
8490
#[inline]
8591
pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
86-
Self::new(x, Display::fmt)
92+
argument_new!(T, x, <T as Display>::fmt)
8793
}
8894
#[inline]
8995
pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
90-
Self::new(x, Debug::fmt)
96+
argument_new!(T, x, <T as Debug>::fmt)
9197
}
9298
#[inline]
9399
pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
94-
Self::new(x, |_, _| Ok(()))
100+
argument_new!(T, x, |_: &T, _| Ok(()))
95101
}
96102
#[inline]
97103
pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
98-
Self::new(x, Octal::fmt)
104+
argument_new!(T, x, <T as Octal>::fmt)
99105
}
100106
#[inline]
101107
pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
102-
Self::new(x, LowerHex::fmt)
108+
argument_new!(T, x, <T as LowerHex>::fmt)
103109
}
104110
#[inline]
105111
pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
106-
Self::new(x, UpperHex::fmt)
112+
argument_new!(T, x, <T as UpperHex>::fmt)
107113
}
108114
#[inline]
109115
pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
110-
Self::new(x, Pointer::fmt)
116+
argument_new!(T, x, <T as Pointer>::fmt)
111117
}
112118
#[inline]
113119
pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
114-
Self::new(x, Binary::fmt)
120+
argument_new!(T, x, <T as Binary>::fmt)
115121
}
116122
#[inline]
117123
pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
118-
Self::new(x, LowerExp::fmt)
124+
argument_new!(T, x, <T as LowerExp>::fmt)
119125
}
120126
#[inline]
121127
pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
122-
Self::new(x, UpperExp::fmt)
128+
argument_new!(T, x, <T as UpperExp>::fmt)
123129
}
124130
#[inline]
125131
#[track_caller]
@@ -135,11 +141,6 @@ impl Argument<'_> {
135141
/// # Safety
136142
///
137143
/// 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)]
143144
#[inline]
144145
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
145146
match self.ty {

0 commit comments

Comments
 (0)