From bda12a6bc053fd05e342678413914baf9858f4d9 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Wed, 30 Dec 2020 02:33:18 -0800 Subject: [PATCH] Ignore vtables in {Rc, Arc, Weak}::ptr_eq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We sometimes generate duplicate vtables depending on the number of codegen units (#46139), so we need to exclude the vtable part when comparing fat pointers. This is safe for the case of Rc, Arc, and Weak because these always point to an entire allocation. These methods can’t be used to compare, e.g., a struct with one of its fields, a slice with one of its subslices, or consecutive ZST fields. Fixes #63021. Signed-off-by: Anders Kaseorg --- library/alloc/src/rc.rs | 8 ++++++-- library/alloc/src/sync.rs | 8 ++++++-- library/alloc/tests/arc.rs | 17 +++++++++++++++++ library/alloc/tests/rc.rs | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index ee03f15eece3f..8f1531eccafcc 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1002,7 +1002,9 @@ impl Rc { /// /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + // The *const u8 cast discards the vtable to work around + // https://github.com/rust-lang/rust/issues/46139 + this.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8 } } @@ -2136,7 +2138,9 @@ impl Weak { #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + // The *const u8 cast discards the vtable to work around + // https://github.com/rust-lang/rust/issues/46139 + self.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8 } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c0d684fbb4573..0889bf5519894 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1066,7 +1066,9 @@ impl Arc { /// /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + // The *const u8 cast discards the vtable to work around + // https://github.com/rust-lang/rust/issues/46139 + this.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8 } } @@ -1936,7 +1938,9 @@ impl Weak { #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + // The *const u8 cast discards the vtable to work around + // https://github.com/rust-lang/rust/issues/46139 + self.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8 } } diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index c02ba267056d6..8a498f305c621 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -195,3 +195,20 @@ fn shared_from_iter_trustedlen_no_fuse() { assert_trusted_len(&iter); assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); } + +mod other_mod { + use std::sync::Arc; + + pub fn cast(r: Arc<()>) -> Arc { + r + } +} + +#[test] +fn ptr_eq_ignores_duplicated_vtable() { + let a = Arc::new(()); + let b = other_mod::cast(Arc::clone(&a)); + let c: Arc = a; + assert!(Arc::ptr_eq(&b, &c)); + assert!(Weak::ptr_eq(&Arc::downgrade(&b), &Arc::downgrade(&c))); +} diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs index 501b4f0f816be..3e7e7298f0701 100644 --- a/library/alloc/tests/rc.rs +++ b/library/alloc/tests/rc.rs @@ -191,3 +191,20 @@ fn shared_from_iter_trustedlen_no_fuse() { assert_trusted_len(&iter); assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); } + +mod other_mod { + use std::rc::Rc; + + pub fn cast(r: Rc<()>) -> Rc { + r + } +} + +#[test] +fn ptr_eq_ignores_duplicated_vtable() { + let a = Rc::new(()); + let b = other_mod::cast(Rc::clone(&a)); + let c: Rc = a; + assert!(Rc::ptr_eq(&b, &c)); + assert!(Weak::ptr_eq(&Rc::downgrade(&b), &Rc::downgrade(&c))); +}