Rollup merge of #135080 - Enselic:debug-ptr-metadata, r=thomcc
core: Make `Debug` impl of raw pointers print metadata if present Make Rust pointers appear less magic by including metadata information in their `Debug` output. This does not break Rust stability guarantees because `Debug` impl are explicitly exempted from stability: https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability > ## Stability > > Derived `Debug` formats are not stable, and so may change with future Rust versions. Additionally, `Debug` implementations of types provided by the standard library (`std`, `core`, `alloc`, etc.) are not stable, and may also change with future Rust versions. Note that a regression test is added as a separate commit to make it clear what impact the last commit has on the output. Closes #128684 because the output of that code now becomes: ``` thread 'main' panicked at src/main.rs:5:5: assertion `left == right` failed left: Pointer { addr: 0x7ffd45c6fc6b, metadata: 5 } right: Pointer { addr: 0x7ffd45c6fc6b, metadata: 3 } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ```
This commit is contained in:
commit
a23a93cb4e
6 changed files with 86 additions and 3 deletions
|
@ -85,6 +85,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -303,6 +304,31 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
|
|
|
@ -2771,7 +2771,14 @@ impl Display for char {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Pointer for *const T {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
pointer_fmt_inner(self.expose_provenance(), f)
|
||||
if <<T as core::ptr::Pointee>::Metadata as core::unit::IsUnit>::is_unit() {
|
||||
pointer_fmt_inner(self.expose_provenance(), f)
|
||||
} else {
|
||||
f.debug_struct("Pointer")
|
||||
.field_with("addr", |f| pointer_fmt_inner(self.expose_provenance(), f))
|
||||
.field("metadata", &core::ptr::metadata(*self))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ pub trait Pointee {
|
|||
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
|
||||
// in `library/core/src/ptr/metadata.rs`
|
||||
// in sync with those here:
|
||||
// NOTE: The metadata of `dyn Trait + 'a` is `DynMetadata<dyn Trait + 'a>`
|
||||
// so a `'static` bound must not be added.
|
||||
type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,3 +17,19 @@ impl FromIterator<()> for () {
|
|||
iter.into_iter().for_each(|()| {})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait IsUnit {
|
||||
fn is_unit() -> bool;
|
||||
}
|
||||
|
||||
impl<T: ?Sized> IsUnit for T {
|
||||
default fn is_unit() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl IsUnit for () {
|
||||
fn is_unit() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,3 +25,4 @@ test = true
|
|||
[dev-dependencies]
|
||||
rand = { version = "0.9.0", default-features = false }
|
||||
rand_xorshift = { version = "0.4.0", default-features = false }
|
||||
regex = { version = "1.11.1", default-features = false }
|
||||
|
|
|
@ -15,8 +15,39 @@ fn test_format_flags() {
|
|||
fn test_pointer_formats_data_pointer() {
|
||||
let b: &[u8] = b"";
|
||||
let s: &str = "";
|
||||
assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
|
||||
assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
|
||||
assert_eq!(format!("{s:p}"), format!("{:p}", s as *const _));
|
||||
assert_eq!(format!("{b:p}"), format!("{:p}", b as *const _));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_debug_of_raw_pointers() {
|
||||
use core::fmt::Debug;
|
||||
|
||||
fn check_fmt<T: Debug>(t: T, expected: &str) {
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
static ADDR_REGEX: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"0x[0-9a-fA-F]+").unwrap());
|
||||
|
||||
let formatted = format!("{:?}", t);
|
||||
let normalized = ADDR_REGEX.replace_all(&formatted, "$$HEX");
|
||||
|
||||
assert_eq!(normalized, expected);
|
||||
}
|
||||
|
||||
let plain = &mut 100;
|
||||
check_fmt(plain as *mut i32, "$HEX");
|
||||
check_fmt(plain as *const i32, "$HEX");
|
||||
|
||||
let slice = &mut [200, 300, 400][..];
|
||||
check_fmt(slice as *mut [i32], "Pointer { addr: $HEX, metadata: 3 }");
|
||||
check_fmt(slice as *const [i32], "Pointer { addr: $HEX, metadata: 3 }");
|
||||
|
||||
let vtable = &mut 500 as &mut dyn Debug;
|
||||
check_fmt(vtable as *mut dyn Debug, "Pointer { addr: $HEX, metadata: DynMetadata($HEX) }");
|
||||
check_fmt(vtable as *const dyn Debug, "Pointer { addr: $HEX, metadata: DynMetadata($HEX) }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue