Skip to content

Commit 47a90f4

Browse files
committed
Auto merge of rust-lang#85535 - dtolnay:weakdangle, r=kennytm
Weak's type parameter may dangle on drop Way back in rust-lang@34076bc, #\[may_dangle\] was added to Rc\<T\> and Arc\<T\>'s Drop impls. That appears to have been because a test added in rust-lang#28929 used Arc and Rc with dangling references at drop time. However, Weak was not covered by that test, and therefore no #\[may_dangle\] was forced to be added at the time. As far as dropping, Weak has *even less need* to interact with the T than Rc and Arc do. Roughly speaking #\[may_dangle\] describes generic parameters that the outer type's Drop impl does not interact with except by possibly dropping them; no other interaction (such as trait method calls on the generic type) is permissible. It's clear this applies to Rc's and Arc's drop impl, which sometimes drop T but otherwise do not interact with one. It applies *even more* to Weak. Dropping a Weak cannot ever cause T's drop impl to run. Either there are strong references still in existence, in which case better not drop the T. Or there are no strong references still in existence, in which case the T would already have been dropped previously by the drop of the last strong count.
2 parents ff2c947 + 23a4050 commit 47a90f4

File tree

4 files changed

+32
-2
lines changed

4 files changed

+32
-2
lines changed

library/alloc/src/rc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2303,7 +2303,7 @@ impl<T: ?Sized> Weak<T> {
23032303
}
23042304

23052305
#[stable(feature = "rc_weak", since = "1.4.0")]
2306-
impl<T: ?Sized> Drop for Weak<T> {
2306+
unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
23072307
/// Drops the `Weak` pointer.
23082308
///
23092309
/// # Examples

library/alloc/src/sync.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2015,7 +2015,7 @@ impl<T> Default for Weak<T> {
20152015
}
20162016

20172017
#[stable(feature = "arc_weak", since = "1.4.0")]
2018-
impl<T: ?Sized> Drop for Weak<T> {
2018+
unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
20192019
/// Drops the `Weak` pointer.
20202020
///
20212021
/// # Examples

library/alloc/tests/arc.rs

+15
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,18 @@ 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+
#[test]
200+
fn weak_may_dangle() {
201+
fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
202+
val.clone()
203+
}
204+
205+
// Without #[may_dangle] we get:
206+
let mut val = Weak::new();
207+
hmm(&mut val);
208+
// ~~~~~~~~ borrowed value does not live long enough
209+
//
210+
// `val` dropped here while still borrowed
211+
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
212+
}

library/alloc/tests/rc.rs

+15
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,18 @@ 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+
#[test]
196+
fn weak_may_dangle() {
197+
fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
198+
val.clone()
199+
}
200+
201+
// Without #[may_dangle] we get:
202+
let mut val = Weak::new();
203+
hmm(&mut val);
204+
// ~~~~~~~~ borrowed value does not live long enough
205+
//
206+
// `val` dropped here while still borrowed
207+
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
208+
}

0 commit comments

Comments
 (0)