Skip to content

Commit

Permalink
Move the show_usize marker function to a static
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Mark-Simulacrum committed Feb 17, 2020
1 parent 34ef8f5 commit f6bfdc9
Showing 1 changed file with 16 additions and 7 deletions.
23 changes: 16 additions & 7 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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
Expand Down

0 comments on commit f6bfdc9

Please sign in to comment.