about summary refs log tree commit diff
path: root/src/libcore/fmt
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2020-02-16 10:17:01 -0500
committerMark Rousskov <mark.simulacrum@gmail.com>2020-02-17 09:18:33 -0500
commitf6bfdc95445180aee579dcacc6e6bdc4e6ecf56f (patch)
tree6fe6da3b410876a8212136d6795de6e247529f2c /src/libcore/fmt
parent34ef8f5441d5335c4177abd622383ed34a6e9315 (diff)
downloadrust-f6bfdc95445180aee579dcacc6e6bdc4e6ecf56f.tar.gz
rust-f6bfdc95445180aee579dcacc6e6bdc4e6ecf56f.zip
Move the show_usize marker function to a static
Currently, function items are always tagged unnamed_addr, which means that
casting a function to a function pointer is not guaranteed to produce a
deterministic address. However, once a function pointer is created, we do expect
that to remain stable. So, this changes the show_usize function to a static
containing a function pointer and uses that for comparisons.

Notably, a *static* may have 'unstable' address, but the function pointer within
it must be constant.

Resolves issue 58320.
Diffstat (limited to 'src/libcore/fmt')
-rw-r--r--src/libcore/fmt/mod.rs23
1 files changed, 16 insertions, 7 deletions
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 0c51a802fab..993b1073493 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -255,12 +255,19 @@ pub struct ArgumentV1<'a> {
     formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
 }
 
-impl<'a> ArgumentV1<'a> {
-    #[inline(never)]
-    fn show_usize(x: &usize, f: &mut Formatter<'_>) -> Result {
-        Display::fmt(x, f)
-    }
+// This gurantees a single stable value for the function pointer associated with
+// indices/counts in the formatting infrastructure.
+//
+// Note that a function defined as such would not be correct as functions are
+// always tagged unnamed_addr with the current lowering to LLVM IR, so their
+// address is not considered important to LLVM and as such the as_usize cast
+// could have been miscompiled. In practice, we never call as_usize on non-usize
+// containing data (as a matter of static generation of the formatting
+// arguments), so this is merely an additional check.
+#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |_, _| loop {};
 
+impl<'a> ArgumentV1<'a> {
     #[doc(hidden)]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
     pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
@@ -270,11 +277,13 @@ impl<'a> ArgumentV1<'a> {
     #[doc(hidden)]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
-        ArgumentV1::new(x, ArgumentV1::show_usize)
+        ArgumentV1::new(x, USIZE_MARKER)
     }
 
     fn as_usize(&self) -> Option<usize> {
-        if self.formatter as usize == ArgumentV1::show_usize as usize {
+        if self.formatter as usize == USIZE_MARKER as usize {
+            // SAFETY: The `formatter` field is only set to USIZE_MARKER if
+            // the value is a usize, so this is safe
             Some(unsafe { *(self.value as *const _ as *const usize) })
         } else {
             None