Skip to content

Commit

Permalink
fmt: Debug-format fat pointers with their metadata for better insight
Browse files Browse the repository at this point in the history
Use ptr::metadata() fn to improve debug prints of fat pointers.

Co-authored-by: Mara Bos <m-ou.se@m-ou.se>
  • Loading branch information
vojtechkral and m-ou-se committed Feb 7, 2022
1 parent 498eeb7 commit 30e5888
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 4 deletions.
40 changes: 38 additions & 2 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
use crate::char::EscapeDebugExtArgs;
use crate::marker::PhantomData;
use crate::mem;
use crate::ptr::{self, DynMetadata};
use crate::num::fmt as numfmt;
use crate::ops::Deref;
use crate::result;
Expand Down Expand Up @@ -2281,16 +2282,51 @@ impl<T: ?Sized> Pointer for &mut T {

// Implementation of Display/Debug for various core types

/// A local trait for pointer Debug impl so that we can have
/// min_specialization-compliant specializations for two types of fat ptrs.
trait PtrMetadataFmt {
fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result;
}

// Regular pointer / default impl
impl<T> PtrMetadataFmt for T {
#[inline]
default fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result {
Pointer::fmt(&ptr, f)
}
}

// Pointer + length
impl PtrMetadataFmt for usize {
#[inline]
fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result {
write!(f, "({:p}, {})", ptr, *self)
}
}

// Pointer + vtable
impl<Dyn: ?Sized> PtrMetadataFmt for DynMetadata<Dyn> {
#[inline]
fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result {
f.debug_tuple("")
.field(&ptr)
.field(self)
.finish()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Debug for *const T {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
Pointer::fmt(self, f)
let meta = ptr::metadata(*self);
meta.fmt_ptr(*self as *const (), f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Debug for *mut T {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
Pointer::fmt(self, f)
let ptr: *const T = *self;
Debug::fmt(&ptr, f)
}
}

Expand Down
38 changes: 36 additions & 2 deletions library/core/tests/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ mod builders;
mod float;
mod num;

use core::any::Any;
use core::fmt;
use core::ptr;

#[test]
fn test_format_flags() {
// No residual flags left by pointer formatting
Expand All @@ -19,6 +23,36 @@ fn test_pointer_formats_data_pointer() {
assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr()));
}

#[test]
fn test_pointer_formats_debug_thin() {
let thinptr = &42 as *const i32;
assert_eq!(format!("{:?}", thinptr as *const ()), format!("{:p}", thinptr));
}

#[test]
fn test_pointer_formats_debug_slice() {
let b: &[u8] = b"hello";
let s: &str = "hello";
let b_ptr = &*b as *const _;
let s_ptr = &*s as *const _;
assert_eq!(format!("{:?}", b_ptr), format!("({:?}, 5)", b.as_ptr()));
assert_eq!(format!("{:?}", s_ptr), format!("({:?}, 5)", s.as_ptr()));

// :p should format as a thin pointer / without metadata
assert_eq!(format!("{:p}", b_ptr), format!("{:p}", b.as_ptr()));
assert_eq!(format!("{:p}", s_ptr), format!("{:p}", s.as_ptr()));
}

#[test]
fn test_pointer_formats_debug_trait_object() {
let mut any: Box<dyn Any> = Box::new(42);
let dyn_ptr = &mut *any as *mut dyn Any;
assert_eq!(format!("{:?}", dyn_ptr), format!("({:?}, {:?})", dyn_ptr as *const (), ptr::metadata(dyn_ptr)));

// :p should format as a thin pointer / without metadata
assert_eq!(format!("{:p}", dyn_ptr), format!("{:p}", dyn_ptr as *const ()));
}

#[test]
fn test_estimated_capacity() {
assert_eq!(format_args!("").estimated_capacity(), 0);
Expand All @@ -33,8 +67,8 @@ fn test_estimated_capacity() {
fn pad_integral_resets() {
struct Bar;

impl core::fmt::Display for Bar {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
impl fmt::Display for Bar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"1".fmt(f)?;
f.pad_integral(true, "", "5")?;
"1".fmt(f)
Expand Down

0 comments on commit 30e5888

Please sign in to comment.