| 1 | #![allow (missing_debug_implementations)] |
| 2 | #![unstable (feature = "fmt_internals" , reason = "internal to format_args!" , issue = "none" )] |
| 3 | |
| 4 | //! All types and methods in this file are used by the compiler in |
| 5 | //! the expansion/lowering of format_args!(). |
| 6 | //! |
| 7 | //! Do not modify them without understanding the consequences for the format_args!() macro. |
| 8 | |
| 9 | use super::*; |
| 10 | use crate::hint::unreachable_unchecked; |
| 11 | use crate::ptr::NonNull; |
| 12 | |
| 13 | #[derive (Copy, Clone)] |
| 14 | enum ArgumentType<'a> { |
| 15 | Placeholder { |
| 16 | // INVARIANT: `formatter` has type `fn(&T, _) -> _` for some `T`, and `value` |
| 17 | // was derived from a `&'a T`. |
| 18 | value: NonNull<()>, |
| 19 | formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result, |
| 20 | _lifetime: PhantomData<&'a ()>, |
| 21 | }, |
| 22 | Count(u16), |
| 23 | } |
| 24 | |
| 25 | /// This struct represents a generic "argument" which is taken by format_args!(). |
| 26 | /// |
| 27 | /// This can be either a placeholder argument or a count argument. |
| 28 | /// * A placeholder argument contains a function to format the given value. At |
| 29 | /// compile time it is ensured that the function and the value have the correct |
| 30 | /// types, and then this struct is used to canonicalize arguments to one type. |
| 31 | /// Placeholder arguments are essentially an optimized partially applied formatting |
| 32 | /// function, equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. |
| 33 | /// * A count argument contains a count for dynamic formatting parameters like |
| 34 | /// precision and width. |
| 35 | #[lang = "format_argument" ] |
| 36 | #[derive (Copy, Clone)] |
| 37 | #[repr (align(2))] // To ensure pointers to this struct always have their lowest bit cleared. |
| 38 | pub struct Argument<'a> { |
| 39 | ty: ArgumentType<'a>, |
| 40 | } |
| 41 | |
| 42 | macro_rules! argument_new { |
| 43 | ($t:ty, $x:expr, $f:expr) => { |
| 44 | Argument { |
| 45 | // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and |
| 46 | // a `fn(&T, ...)`, so the invariant is maintained. |
| 47 | ty: ArgumentType::Placeholder { |
| 48 | value: NonNull::<$t>::from_ref($x).cast(), |
| 49 | // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to |
| 50 | // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed. |
| 51 | // However, the CFI sanitizer does not allow this, and triggers a crash when it |
| 52 | // happens. |
| 53 | // |
| 54 | // To avoid this crash, we use a helper function when CFI is enabled. To avoid the |
| 55 | // cost of this helper function (mainly code-size) when it is not needed, we |
| 56 | // transmute the function pointer otherwise. |
| 57 | // |
| 58 | // This is similar to what the Rust compiler does internally with vtables when KCFI |
| 59 | // is enabled, where it generates trampoline functions that only serve to adjust the |
| 60 | // expected type of the argument. `ArgumentType::Placeholder` is a bit like a |
| 61 | // manually constructed trait object, so it is not surprising that the same approach |
| 62 | // has to be applied here as well. |
| 63 | // |
| 64 | // It is still considered problematic (from the Rust side) that CFI rejects entirely |
| 65 | // legal Rust programs, so we do not consider anything done here a stable guarantee, |
| 66 | // but meanwhile we carry this work-around to keep Rust compatible with CFI and |
| 67 | // KCFI. |
| 68 | #[cfg(not(any(sanitize = "cfi" , sanitize = "kcfi" )))] |
| 69 | formatter: { |
| 70 | let f: fn(&$t, &mut Formatter<'_>) -> Result = $f; |
| 71 | // SAFETY: This is only called with `value`, which has the right type. |
| 72 | unsafe { core::mem::transmute(f) } |
| 73 | }, |
| 74 | #[cfg(any(sanitize = "cfi" , sanitize = "kcfi" ))] |
| 75 | formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { |
| 76 | let func = $f; |
| 77 | // SAFETY: This is the same type as the `value` field. |
| 78 | let r = unsafe { ptr.cast::<$t>().as_ref() }; |
| 79 | (func)(r, fmt) |
| 80 | }, |
| 81 | _lifetime: PhantomData, |
| 82 | }, |
| 83 | } |
| 84 | }; |
| 85 | } |
| 86 | |
| 87 | impl Argument<'_> { |
| 88 | #[inline ] |
| 89 | pub const fn new_display<T: Display>(x: &T) -> Argument<'_> { |
| 90 | argument_new!(T, x, <T as Display>::fmt) |
| 91 | } |
| 92 | #[inline ] |
| 93 | pub const fn new_debug<T: Debug>(x: &T) -> Argument<'_> { |
| 94 | argument_new!(T, x, <T as Debug>::fmt) |
| 95 | } |
| 96 | #[inline ] |
| 97 | pub const fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> { |
| 98 | argument_new!(T, x, |_: &T, _| Ok(())) |
| 99 | } |
| 100 | #[inline ] |
| 101 | pub const fn new_octal<T: Octal>(x: &T) -> Argument<'_> { |
| 102 | argument_new!(T, x, <T as Octal>::fmt) |
| 103 | } |
| 104 | #[inline ] |
| 105 | pub const fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> { |
| 106 | argument_new!(T, x, <T as LowerHex>::fmt) |
| 107 | } |
| 108 | #[inline ] |
| 109 | pub const fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> { |
| 110 | argument_new!(T, x, <T as UpperHex>::fmt) |
| 111 | } |
| 112 | #[inline ] |
| 113 | pub const fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> { |
| 114 | argument_new!(T, x, <T as Pointer>::fmt) |
| 115 | } |
| 116 | #[inline ] |
| 117 | pub const fn new_binary<T: Binary>(x: &T) -> Argument<'_> { |
| 118 | argument_new!(T, x, <T as Binary>::fmt) |
| 119 | } |
| 120 | #[inline ] |
| 121 | pub const fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> { |
| 122 | argument_new!(T, x, <T as LowerExp>::fmt) |
| 123 | } |
| 124 | #[inline ] |
| 125 | pub const fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> { |
| 126 | argument_new!(T, x, <T as UpperExp>::fmt) |
| 127 | } |
| 128 | #[inline ] |
| 129 | #[track_caller ] |
| 130 | pub const fn from_usize(x: &usize) -> Argument<'_> { |
| 131 | if *x > u16::MAX as usize { |
| 132 | panic!("Formatting argument out of range" ); |
| 133 | } |
| 134 | Argument { ty: ArgumentType::Count(*x as u16) } |
| 135 | } |
| 136 | |
| 137 | /// Format this placeholder argument. |
| 138 | /// |
| 139 | /// # Safety |
| 140 | /// |
| 141 | /// This argument must actually be a placeholder argument. |
| 142 | #[inline ] |
| 143 | pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { |
| 144 | match self.ty { |
| 145 | // SAFETY: |
| 146 | // Because of the invariant that if `formatter` had the type |
| 147 | // `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is |
| 148 | // the lifetime of the `ArgumentType`, and because references |
| 149 | // and `NonNull` are ABI-compatible, this is completely equivalent |
| 150 | // to calling the original function passed to `new` with the |
| 151 | // original reference, which is sound. |
| 152 | ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) }, |
| 153 | // SAFETY: the caller promised this. |
| 154 | ArgumentType::Count(_) => unsafe { unreachable_unchecked() }, |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | #[inline ] |
| 159 | pub(super) const fn as_u16(&self) -> Option<u16> { |
| 160 | match self.ty { |
| 161 | ArgumentType::Count(count) => Some(count), |
| 162 | ArgumentType::Placeholder { .. } => None, |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |