From db539c649866d9a25cb18a741436b3086b5d6e04 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Sun, 28 Jun 2020 14:21:03 -0400 Subject: [PATCH 01/10] Use raw_ref_op in A|Rc::as_ptr --- src/liballoc/lib.rs | 1 + src/liballoc/rc.rs | 6 +----- src/liballoc/sync.rs | 6 +----- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 41c2b221704e6..c812d0c631618 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -109,6 +109,7 @@ #![feature(pattern)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] +#![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(min_specialization)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 4d50ae9efca95..c69f2ffc43738 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -591,17 +591,13 @@ impl Rc { #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); - let fake_ptr = ptr as *mut T; // SAFETY: This cannot go through Deref::deref. // Instead, we manually offset the pointer rather than manifesting a reference. // This is so that the returned pointer retains the same provenance as our pointer. // This is required so that e.g. `get_mut` can write through the pointer // after the Rc is recovered through `from_raw`. - unsafe { - let offset = data_offset(&(*ptr).value); - set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset)) - } + unsafe { &raw const (*ptr).value } } /// Constructs an `Rc` from a raw pointer. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 826f0c8fa833f..5a9ab24562a30 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -590,17 +590,13 @@ impl Arc { #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); - let fake_ptr = ptr as *mut T; // SAFETY: This cannot go through Deref::deref. // Instead, we manually offset the pointer rather than manifesting a reference. // This is so that the returned pointer retains the same provenance as our pointer. // This is required so that e.g. `get_mut` can write through the pointer // after the Arc is recovered through `from_raw`. - unsafe { - let offset = data_offset(&(*ptr).data); - set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset)) - } + unsafe { &raw const (*ptr).data } } /// Constructs an `Arc` from a raw pointer. From e4bdf47f4c0773bba93f50900612242b929eca0b Mon Sep 17 00:00:00 2001 From: CAD97 Date: Sun, 28 Jun 2020 14:24:09 -0400 Subject: [PATCH 02/10] Do not require ptr validity in rc::data_offset --- src/liballoc/lib.rs | 1 + src/liballoc/rc.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c812d0c631618..ed3b09bae0540 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -100,6 +100,7 @@ #![feature(fundamental)] #![feature(internal_uninit_const)] #![feature(lang_items)] +#![feature(layout_for_ptr)] #![feature(libc)] #![feature(negative_impls)] #![feature(new_uninit)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c69f2ffc43738..408278d5b615e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -245,7 +245,7 @@ use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::iter; use core::marker::{self, PhantomData, Unpin, Unsize}; -use core::mem::{self, align_of, align_of_val, forget, size_of_val}; +use core::mem::{self, align_of, align_of_val_raw, forget, size_of_val}; use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -2114,7 +2114,7 @@ unsafe fn data_offset(ptr: *const T) -> isize { // Because it is ?Sized, it will always be the last field in memory. // Note: This is a detail of the current implementation of the compiler, // and is not a guaranteed language detail. Do not rely on it outside of std. - unsafe { data_offset_align(align_of_val(&*ptr)) } + unsafe { data_offset_align(align_of_val_raw(ptr)) } } /// Computes the offset of the data field within `RcBox`. From d8a9c61e1a23b73c04d3058a11d1b8b2a46d635e Mon Sep 17 00:00:00 2001 From: CAD97 Date: Sun, 28 Jun 2020 14:30:35 -0400 Subject: [PATCH 03/10] Use impl for Weak::as_ptr that works for unsized T --- src/liballoc/rc.rs | 24 +++++++++++++----------- src/liballoc/sync.rs | 24 +++++++++++++----------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 408278d5b615e..423122a690090 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -245,7 +245,7 @@ use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::iter; use core::marker::{self, PhantomData, Unpin, Unsize}; -use core::mem::{self, align_of, align_of_val_raw, forget, size_of_val}; +use core::mem::{self, align_of_val_raw, forget, size_of_val}; use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -1704,9 +1704,18 @@ impl Weak { /// [`null`]: ../../std/ptr/fn.null.html #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { - let offset = data_offset_sized::(); - let ptr = self.ptr.cast::().as_ptr().wrapping_offset(offset); - ptr as *const T + let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); + let fake_ptr = ptr as *mut T; + + // SAFETY: we must offset the pointer manually, and said pointer may be + // a dangling weak (usize::MAX). data_offset is safe to call, because we + // know a pointer to unsized T must be derived from a real unsized T, + // because dangling weaks are only created for sized T. wrapping_offset + // is used so that we can use the same code path for dangling weak refs. + unsafe { + let offset = data_offset(&raw const (*ptr).value); + set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) + } } /// Consumes the `Weak` and turns it into a raw pointer. @@ -2117,13 +2126,6 @@ unsafe fn data_offset(ptr: *const T) -> isize { unsafe { data_offset_align(align_of_val_raw(ptr)) } } -/// Computes the offset of the data field within `RcBox`. -/// -/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`. -fn data_offset_sized() -> isize { - data_offset_align(align_of::()) -} - #[inline] fn data_offset_align(align: usize) -> isize { let layout = Layout::new::>(); diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 5a9ab24562a30..289aea3afcce9 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -16,7 +16,7 @@ use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::iter; use core::marker::{PhantomData, Unpin, Unsize}; -use core::mem::{self, align_of, align_of_val, size_of_val}; +use core::mem::{self, align_of_val, size_of_val}; use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -1472,9 +1472,18 @@ impl Weak { /// [`null`]: ../../std/ptr/fn.null.html #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { - let offset = data_offset_sized::(); - let ptr = self.ptr.cast::().as_ptr().wrapping_offset(offset); - ptr as *const T + let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); + let fake_ptr = ptr as *mut T; + + // SAFETY: we must offset the pointer manually, and said pointer may be + // a dangling weak (usize::MAX). data_offset is safe to call, because we + // know a pointer to unsized T must be derived from a real unsized T, + // because dangling weaks are only created for sized T. wrapping_offset + // is used so that we can use the same code path for dangling weak refs. + unsafe { + let offset = data_offset(&raw const (*ptr).data); + set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) + } } /// Consumes the `Weak` and turns it into a raw pointer. @@ -2275,13 +2284,6 @@ unsafe fn data_offset(ptr: *const T) -> isize { unsafe { data_offset_align(align_of_val(&*ptr)) } } -/// Computes the offset of the data field within `ArcInner`. -/// -/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`. -fn data_offset_sized() -> isize { - data_offset_align(align_of::()) -} - #[inline] fn data_offset_align(align: usize) -> isize { let layout = Layout::new::>(); From fc3dc723da8daef495a170e02efb38093e05215e Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 30 Jun 2020 12:35:28 -0400 Subject: [PATCH 04/10] Clarify safety comment for A|Rc::as_ptr --- src/liballoc/rc.rs | 8 +++----- src/liballoc/sync.rs | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 423122a690090..8f7b8efd811f7 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -592,11 +592,9 @@ impl Rc { pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); - // SAFETY: This cannot go through Deref::deref. - // Instead, we manually offset the pointer rather than manifesting a reference. - // This is so that the returned pointer retains the same provenance as our pointer. - // This is required so that e.g. `get_mut` can write through the pointer - // after the Rc is recovered through `from_raw`. + // SAFETY: This cannot go through Deref::deref or Rc::inner. + // This is required to retain raw/mut provenance such that e.g. `get_mut` can + // write through the pointer after the Rc is recovered through `from_raw`. unsafe { &raw const (*ptr).value } } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 289aea3afcce9..27c36f4a56933 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -591,11 +591,9 @@ impl Arc { pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); - // SAFETY: This cannot go through Deref::deref. - // Instead, we manually offset the pointer rather than manifesting a reference. - // This is so that the returned pointer retains the same provenance as our pointer. - // This is required so that e.g. `get_mut` can write through the pointer - // after the Arc is recovered through `from_raw`. + // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner. + // This is required to retain raw/mut provenance such that e.g. `get_mut` can + // write through the pointer after the Rc is recovered through `from_raw`. unsafe { &raw const (*ptr).data } } From 0aecf3c74b7fd09460f453e7e95ae8cb65a92440 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 30 Jun 2020 12:42:09 -0400 Subject: [PATCH 05/10] Fix invalid pointer deref in Weak::as_ptr --- src/liballoc/rc.rs | 2 +- src/liballoc/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 8f7b8efd811f7..ab64d5330874f 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -1711,7 +1711,7 @@ impl Weak { // because dangling weaks are only created for sized T. wrapping_offset // is used so that we can use the same code path for dangling weak refs. unsafe { - let offset = data_offset(&raw const (*ptr).value); + let offset = data_offset(fake_ptr); set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) } } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 27c36f4a56933..e9af80d326f44 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -1479,7 +1479,7 @@ impl Weak { // because dangling weaks are only created for sized T. wrapping_offset // is used so that we can use the same code path for dangling weak refs. unsafe { - let offset = data_offset(&raw const (*ptr).data); + let offset = data_offset(fake_ptr); set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) } } From aed88e18049f6be7d3c3b37683d05d777adb3c86 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 30 Jun 2020 12:47:23 -0400 Subject: [PATCH 06/10] Clarify when rc::data_offset is safe --- src/liballoc/rc.rs | 10 ++++++++++ src/liballoc/sync.rs | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index ab64d5330874f..24e7d5da7a684 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -2116,6 +2116,16 @@ impl AsRef for Rc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc {} +/// Get the offset within an `ArcInner` for +/// a payload of type described by a pointer. +/// +/// # Safety +/// +/// This has the same safety requirements as `align_of_val_raw`. In effect: +/// +/// - This function is safe for any argument if `T` is sized, and +/// - if `T` is unsized, the pointer must have appropriate pointer metadata +/// aquired from the real instance that you are getting this offset for. unsafe fn data_offset(ptr: *const T) -> isize { // Align the unsized value to the end of the `RcBox`. // Because it is ?Sized, it will always be the last field in memory. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index e9af80d326f44..53ce47d023b47 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -2273,7 +2273,16 @@ impl AsRef for Arc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Arc {} -/// Computes the offset of the data field within `ArcInner`. +/// Get the offset within an `ArcInner` for +/// a payload of type described by a pointer. +/// +/// # Safety +/// +/// This has the same safety requirements as `align_of_val_raw`. In effect: +/// +/// - This function is safe for any argument if `T` is sized, and +/// - if `T` is unsized, the pointer must have appropriate pointer metadata +/// aquired from the real instance that you are getting this offset for. unsafe fn data_offset(ptr: *const T) -> isize { // Align the unsized value to the end of the `ArcInner`. // Because it is `?Sized`, it will always be the last field in memory. From ac40d1eff33cc6789d3c02f4a21477368574cf5e Mon Sep 17 00:00:00 2001 From: CAD97 Date: Wed, 1 Jul 2020 14:51:08 -0400 Subject: [PATCH 07/10] Apply documentation review suggestions Co-Authored-By: Ralf Jung --- src/liballoc/rc.rs | 7 ++++--- src/liballoc/sync.rs | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 24e7d5da7a684..29e0979b0eda6 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -592,8 +592,8 @@ impl Rc { pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); - // SAFETY: This cannot go through Deref::deref or Rc::inner. - // This is required to retain raw/mut provenance such that e.g. `get_mut` can + // SAFETY: This cannot go through Deref::deref or Rc::inner because + // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. unsafe { &raw const (*ptr).value } } @@ -1709,7 +1709,8 @@ impl Weak { // a dangling weak (usize::MAX). data_offset is safe to call, because we // know a pointer to unsized T must be derived from a real unsized T, // because dangling weaks are only created for sized T. wrapping_offset - // is used so that we can use the same code path for dangling weak refs. + // is used so that we can use the same code path for the non-dangling + // unsized case and the potentially dangling sized case. unsafe { let offset = data_offset(fake_ptr); set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 53ce47d023b47..005821980fe2c 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -591,8 +591,8 @@ impl Arc { pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); - // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner. - // This is required to retain raw/mut provenance such that e.g. `get_mut` can + // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because + // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. unsafe { &raw const (*ptr).data } } @@ -1477,7 +1477,8 @@ impl Weak { // a dangling weak (usize::MAX). data_offset is safe to call, because we // know a pointer to unsized T must be derived from a real unsized T, // because dangling weaks are only created for sized T. wrapping_offset - // is used so that we can use the same code path for dangling weak refs. + // is used so that we can use the same code path for the non-dangling + // unsized case and the potentially dangling sized case. unsafe { let offset = data_offset(fake_ptr); set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) From 98789ac75a15c78462ada2438881c8a4e4fda94a Mon Sep 17 00:00:00 2001 From: CAD97 Date: Wed, 1 Jul 2020 15:03:12 -0400 Subject: [PATCH 08/10] Simplify Weak::as_ptr impl --- src/liballoc/rc.rs | 5 ++--- src/liballoc/sync.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 29e0979b0eda6..4d77779b2091d 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -1703,7 +1703,6 @@ impl Weak { #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); - let fake_ptr = ptr as *mut T; // SAFETY: we must offset the pointer manually, and said pointer may be // a dangling weak (usize::MAX). data_offset is safe to call, because we @@ -1712,8 +1711,8 @@ impl Weak { // is used so that we can use the same code path for the non-dangling // unsized case and the potentially dangling sized case. unsafe { - let offset = data_offset(fake_ptr); - set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) + let offset = data_offset(ptr as *mut T); + set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset)) } } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 005821980fe2c..160abe7210c77 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -1471,7 +1471,6 @@ impl Weak { #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); - let fake_ptr = ptr as *mut T; // SAFETY: we must offset the pointer manually, and said pointer may be // a dangling weak (usize::MAX). data_offset is safe to call, because we @@ -1480,8 +1479,8 @@ impl Weak { // is used so that we can use the same code path for the non-dangling // unsized case and the potentially dangling sized case. unsafe { - let offset = data_offset(fake_ptr); - set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset)) + let offset = data_offset(ptr as *mut T); + set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset)) } } From 7498cad0d8dacd51f0d18bdf985c15efe55b4e8a Mon Sep 17 00:00:00 2001 From: CAD97 Date: Wed, 1 Jul 2020 16:01:34 -0400 Subject: [PATCH 09/10] Reclarify safety comments in Weak::as_ptr --- src/liballoc/rc.rs | 6 +++--- src/liballoc/sync.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 4d77779b2091d..835df66d55c4e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -1705,9 +1705,9 @@ impl Weak { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); // SAFETY: we must offset the pointer manually, and said pointer may be - // a dangling weak (usize::MAX). data_offset is safe to call, because we - // know a pointer to unsized T must be derived from a real unsized T, - // because dangling weaks are only created for sized T. wrapping_offset + // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call, + // because we know that a pointer to unsized T was derived from a real + // unsized T, as dangling weaks are only created for sized T. wrapping_offset // is used so that we can use the same code path for the non-dangling // unsized case and the potentially dangling sized case. unsafe { diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 160abe7210c77..875bec5b20372 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -1473,9 +1473,9 @@ impl Weak { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); // SAFETY: we must offset the pointer manually, and said pointer may be - // a dangling weak (usize::MAX). data_offset is safe to call, because we - // know a pointer to unsized T must be derived from a real unsized T, - // because dangling weaks are only created for sized T. wrapping_offset + // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call, + // because we know that a pointer to unsized T was derived from a real + // unsized T, as dangling weaks are only created for sized T. wrapping_offset // is used so that we can use the same code path for the non-dangling // unsized case and the potentially dangling sized case. unsafe { From 1b5ac57bfd4b0cca3bcdd0fa75c0f0e044ebf01e Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 2 Jul 2020 16:53:56 -0400 Subject: [PATCH 10/10] Note Weak.ptr never dangles sooner --- src/liballoc/rc.rs | 1 + src/liballoc/sync.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 835df66d55c4e..fccdfa0dca92a 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -1641,6 +1641,7 @@ pub struct Weak { // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer // will ever have because RcBox has alignment at least 2. + // This is only possible when `T: Sized`; unsized `T` never dangle. ptr: NonNull>, } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 875bec5b20372..ac3ce2255c89b 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -267,6 +267,7 @@ pub struct Weak { // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer // will ever have because RcBox has alignment at least 2. + // This is only possible when `T: Sized`; unsized `T` never dangle. ptr: NonNull>, }