Skip to content

Commit bda12a6

Browse files
committed
Ignore vtables in {Rc, Arc, Weak}::ptr_eq
We sometimes generate duplicate vtables depending on the number of codegen units (rust-lang#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 rust-lang#63021. Signed-off-by: Anders Kaseorg <andersk@mit.edu>
1 parent 9a9477f commit bda12a6

File tree

4 files changed

+46
-4
lines changed

4 files changed

+46
-4
lines changed

library/alloc/src/rc.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,9 @@ impl<T: ?Sized> Rc<T> {
10021002
///
10031003
/// [`ptr::eq`]: core::ptr::eq
10041004
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
1005-
this.ptr.as_ptr() == other.ptr.as_ptr()
1005+
// The *const u8 cast discards the vtable to work around
1006+
// https://github.com/rust-lang/rust/issues/46139
1007+
this.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8
10061008
}
10071009
}
10081010

@@ -2136,7 +2138,9 @@ impl<T: ?Sized> Weak<T> {
21362138
#[inline]
21372139
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
21382140
pub fn ptr_eq(&self, other: &Self) -> bool {
2139-
self.ptr.as_ptr() == other.ptr.as_ptr()
2141+
// The *const u8 cast discards the vtable to work around
2142+
// https://github.com/rust-lang/rust/issues/46139
2143+
self.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8
21402144
}
21412145
}
21422146

library/alloc/src/sync.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,9 @@ impl<T: ?Sized> Arc<T> {
10661066
///
10671067
/// [`ptr::eq`]: core::ptr::eq
10681068
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
1069-
this.ptr.as_ptr() == other.ptr.as_ptr()
1069+
// The *const u8 cast discards the vtable to work around
1070+
// https://github.com/rust-lang/rust/issues/46139
1071+
this.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8
10701072
}
10711073
}
10721074

@@ -1936,7 +1938,9 @@ impl<T: ?Sized> Weak<T> {
19361938
#[inline]
19371939
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
19381940
pub fn ptr_eq(&self, other: &Self) -> bool {
1939-
self.ptr.as_ptr() == other.ptr.as_ptr()
1941+
// The *const u8 cast discards the vtable to work around
1942+
// https://github.com/rust-lang/rust/issues/46139
1943+
self.ptr.as_ptr() as *const u8 == other.ptr.as_ptr() as *const u8
19401944
}
19411945
}
19421946

library/alloc/tests/arc.rs

+17
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,20 @@ fn shared_from_iter_trustedlen_no_fuse() {
195195
assert_trusted_len(&iter);
196196
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
197197
}
198+
199+
mod other_mod {
200+
use std::sync::Arc;
201+
202+
pub fn cast(r: Arc<()>) -> Arc<dyn Send> {
203+
r
204+
}
205+
}
206+
207+
#[test]
208+
fn ptr_eq_ignores_duplicated_vtable() {
209+
let a = Arc::new(());
210+
let b = other_mod::cast(Arc::clone(&a));
211+
let c: Arc<dyn Send> = a;
212+
assert!(Arc::ptr_eq(&b, &c));
213+
assert!(Weak::ptr_eq(&Arc::downgrade(&b), &Arc::downgrade(&c)));
214+
}

library/alloc/tests/rc.rs

+17
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,20 @@ fn shared_from_iter_trustedlen_no_fuse() {
191191
assert_trusted_len(&iter);
192192
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
193193
}
194+
195+
mod other_mod {
196+
use std::rc::Rc;
197+
198+
pub fn cast(r: Rc<()>) -> Rc<dyn Send> {
199+
r
200+
}
201+
}
202+
203+
#[test]
204+
fn ptr_eq_ignores_duplicated_vtable() {
205+
let a = Rc::new(());
206+
let b = other_mod::cast(Rc::clone(&a));
207+
let c: Rc<dyn Send> = a;
208+
assert!(Rc::ptr_eq(&b, &c));
209+
assert!(Weak::ptr_eq(&Rc::downgrade(&b), &Rc::downgrade(&c)));
210+
}

0 commit comments

Comments
 (0)