Skip to content

Commit 6c49d0d

Browse files
authored
Unrolled build for rust-lang#125093
Rollup merge of rust-lang#125093 - zachs18:rc-into-raw-with-allocator-only, r=Mark-Simulacrum Add `fn into_raw_with_allocator` to Rc/Arc/Weak. Split out from rust-lang#119761 Add `fn into_raw_with_allocator` for `Rc`/`rc::Weak`[^1]/`Arc`/`sync::Weak`. * Pairs with `from_raw_in` (which already exists on all 4 types). * Name matches `Box::into_raw_with_allocator`. * Associated fns on `Rc`/`Arc`, methods on `Weak`s. <details> <summary>Future PR/ACP</summary> As a follow-on to this PR, I plan to make a PR/ACP later to move `into_raw(_parts)` from `Container<_, A: Allocator>` to only `Container<_, Global>` (where `Container` = `Vec`/`Box`/`Rc`/`rc::Weak`/`Arc`/`sync::Weak`) so that users of non-`Global` allocators have to explicitly handle the allocator when using `into_raw`-like APIs. The current behaviors of stdlib containers are inconsistent with respect to what happens to the allocator when `into_raw` is called (which does not return the allocator) | Type | `into_raw` currently callable with | behavior of `into_raw`| | --- | --- | --- | | `Box` | any allocator | allocator is [dropped](https://doc.rust-lang.org/nightly/src/alloc/boxed.rs.html#1060) | | `Vec` | any allocator | allocator is [forgotten](https://doc.rust-lang.org/nightly/src/alloc/vec/mod.rs.html#884) | | `Arc`/`Rc`/`Weak` | any allocator | allocator is [forgotten](https://doc.rust-lang.org/src/alloc/sync.rs.html#1487)(Arc) [(sync::Weak)](https://doc.rust-lang.org/src/alloc/sync.rs.html#2726) [(Rc)](https://doc.rust-lang.org/src/alloc/rc.rs.html#1352) [(rc::Weak)](https://doc.rust-lang.org/src/alloc/rc.rs.html#2993) | In my opinion, neither implicitly dropping nor implicitly forgetting the allocator is ideal; dropping it could immediately invalidate the returned pointer, and forgetting it could unintentionally leak memory. My (to-be) proposed solution is to just forbid calling `into_raw(_parts)` on containers with non-`Global` allocators, and require calling `into_raw_with_allocator`(/`Vec::into_raw_parts_with_alloc`) </details> [^1]: Technically, `rc::Weak::into_raw_with_allocator` is not newly added, as it was modified and renamed from `rc::Weak::into_raw_and_alloc`.
2 parents f092f73 + c895f6e commit 6c49d0d

File tree

2 files changed

+107
-10
lines changed

2 files changed

+107
-10
lines changed

library/alloc/src/rc.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,33 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
13561356
ptr
13571357
}
13581358

1359+
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
1360+
///
1361+
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1362+
/// [`Rc::from_raw_in`].
1363+
///
1364+
/// # Examples
1365+
///
1366+
/// ```
1367+
/// #![feature(allocator_api)]
1368+
/// use std::rc::Rc;
1369+
/// use std::alloc::System;
1370+
///
1371+
/// let x = Rc::new_in("hello".to_owned(), System);
1372+
/// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
1373+
/// assert_eq!(unsafe { &*ptr }, "hello");
1374+
/// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
1375+
/// assert_eq!(&*x, "hello");
1376+
/// ```
1377+
#[unstable(feature = "allocator_api", issue = "32838")]
1378+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1379+
let this = mem::ManuallyDrop::new(this);
1380+
let ptr = Self::as_ptr(&this);
1381+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1382+
let alloc = unsafe { ptr::read(&this.alloc) };
1383+
(ptr, alloc)
1384+
}
1385+
13591386
/// Provides a raw pointer to the data.
13601387
///
13611388
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -3024,39 +3051,42 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
30243051
result
30253052
}
30263053

3027-
/// Consumes the `Weak<T>` and turns it into a raw pointer.
3054+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
30283055
///
30293056
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
30303057
/// one weak reference (the weak count is not modified by this operation). It can be turned
3031-
/// back into the `Weak<T>` with [`from_raw`].
3058+
/// back into the `Weak<T>` with [`from_raw_in`].
30323059
///
30333060
/// The same restrictions of accessing the target of the pointer as with
30343061
/// [`as_ptr`] apply.
30353062
///
30363063
/// # Examples
30373064
///
30383065
/// ```
3066+
/// #![feature(allocator_api)]
30393067
/// use std::rc::{Rc, Weak};
3068+
/// use std::alloc::System;
30403069
///
3041-
/// let strong = Rc::new("hello".to_owned());
3070+
/// let strong = Rc::new_in("hello".to_owned(), System);
30423071
/// let weak = Rc::downgrade(&strong);
3043-
/// let raw = weak.into_raw();
3072+
/// let (raw, alloc) = weak.into_raw_with_allocator();
30443073
///
30453074
/// assert_eq!(1, Rc::weak_count(&strong));
30463075
/// assert_eq!("hello", unsafe { &*raw });
30473076
///
3048-
/// drop(unsafe { Weak::from_raw(raw) });
3077+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
30493078
/// assert_eq!(0, Rc::weak_count(&strong));
30503079
/// ```
30513080
///
3052-
/// [`from_raw`]: Weak::from_raw
3081+
/// [`from_raw_in`]: Weak::from_raw_in
30533082
/// [`as_ptr`]: Weak::as_ptr
30543083
#[inline]
30553084
#[unstable(feature = "allocator_api", issue = "32838")]
3056-
pub fn into_raw_and_alloc(self) -> (*const T, A) {
3057-
let rc = mem::ManuallyDrop::new(self);
3058-
let result = rc.as_ptr();
3059-
let alloc = unsafe { ptr::read(&rc.alloc) };
3085+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
3086+
let this = mem::ManuallyDrop::new(self);
3087+
let result = this.as_ptr();
3088+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
3089+
let alloc = unsafe { ptr::read(&this.alloc) };
30603090
(result, alloc)
30613091
}
30623092

library/alloc/src/sync.rs

+67
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,34 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
14961496
ptr
14971497
}
14981498

1499+
/// Consumes the `Arc`, returning the wrapped pointer and allocator.
1500+
///
1501+
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
1502+
/// [`Arc::from_raw_in`].
1503+
///
1504+
/// # Examples
1505+
///
1506+
/// ```
1507+
/// #![feature(allocator_api)]
1508+
/// use std::sync::Arc;
1509+
/// use std::alloc::System;
1510+
///
1511+
/// let x = Arc::new_in("hello".to_owned(), System);
1512+
/// let (ptr, alloc) = Arc::into_raw_with_allocator(x);
1513+
/// assert_eq!(unsafe { &*ptr }, "hello");
1514+
/// let x = unsafe { Arc::from_raw_in(ptr, alloc) };
1515+
/// assert_eq!(&*x, "hello");
1516+
/// ```
1517+
#[must_use = "losing the pointer will leak memory"]
1518+
#[unstable(feature = "allocator_api", issue = "32838")]
1519+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1520+
let this = mem::ManuallyDrop::new(this);
1521+
let ptr = Self::as_ptr(&this);
1522+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1523+
let alloc = unsafe { ptr::read(&this.alloc) };
1524+
(ptr, alloc)
1525+
}
1526+
14991527
/// Provides a raw pointer to the data.
15001528
///
15011529
/// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
@@ -2740,6 +2768,45 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
27402768
result
27412769
}
27422770

2771+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
2772+
///
2773+
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
2774+
/// one weak reference (the weak count is not modified by this operation). It can be turned
2775+
/// back into the `Weak<T>` with [`from_raw_in`].
2776+
///
2777+
/// The same restrictions of accessing the target of the pointer as with
2778+
/// [`as_ptr`] apply.
2779+
///
2780+
/// # Examples
2781+
///
2782+
/// ```
2783+
/// #![feature(allocator_api)]
2784+
/// use std::sync::{Arc, Weak};
2785+
/// use std::alloc::System;
2786+
///
2787+
/// let strong = Arc::new_in("hello".to_owned(), System);
2788+
/// let weak = Arc::downgrade(&strong);
2789+
/// let (raw, alloc) = weak.into_raw_with_allocator();
2790+
///
2791+
/// assert_eq!(1, Arc::weak_count(&strong));
2792+
/// assert_eq!("hello", unsafe { &*raw });
2793+
///
2794+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
2795+
/// assert_eq!(0, Arc::weak_count(&strong));
2796+
/// ```
2797+
///
2798+
/// [`from_raw_in`]: Weak::from_raw_in
2799+
/// [`as_ptr`]: Weak::as_ptr
2800+
#[must_use = "losing the pointer will leak memory"]
2801+
#[unstable(feature = "allocator_api", issue = "32838")]
2802+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
2803+
let this = mem::ManuallyDrop::new(self);
2804+
let result = this.as_ptr();
2805+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
2806+
let alloc = unsafe { ptr::read(&this.alloc) };
2807+
(result, alloc)
2808+
}
2809+
27432810
/// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
27442811
/// allocator.
27452812
///

0 commit comments

Comments
 (0)