Skip to content

Commit b8f1fff

Browse files
committed
Change {Box,Arc,Rc,Weak}::into_raw to only work with A = Global
Also applies to `Vec::into_raw_parts`. The expectation is that you can round-trip these methods with `from_raw`, but this is only true when using the global allocator. With custom allocators you should instead be using `into_raw_with_alloc` and `from_raw_in`. Additionally, this PR fixes unsoundness in `Box::leak` when used with a custom allocator: previously the allocator contained in the `Box` was dropped. This is incorrect because for `leak` to be safe, the allocator must not free its underlying backing store. The `Allocator` trait only guarantees that allocated memory remains valid until the allocator is dropped. Fixes #106207
1 parent 4eca99a commit b8f1fff

File tree

3 files changed

+226
-224
lines changed

3 files changed

+226
-224
lines changed

library/alloc/src/boxed.rs

Lines changed: 112 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,115 +1098,6 @@ impl<T: ?Sized> Box<T> {
10981098
pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
10991099
unsafe { Self::from_raw(ptr.as_ptr()) }
11001100
}
1101-
}
1102-
1103-
impl<T: ?Sized, A: Allocator> Box<T, A> {
1104-
/// Constructs a box from a raw pointer in the given allocator.
1105-
///
1106-
/// After calling this function, the raw pointer is owned by the
1107-
/// resulting `Box`. Specifically, the `Box` destructor will call
1108-
/// the destructor of `T` and free the allocated memory. For this
1109-
/// to be safe, the memory must have been allocated in accordance
1110-
/// with the [memory layout] used by `Box` .
1111-
///
1112-
/// # Safety
1113-
///
1114-
/// This function is unsafe because improper use may lead to
1115-
/// memory problems. For example, a double-free may occur if the
1116-
/// function is called twice on the same raw pointer.
1117-
///
1118-
/// The raw pointer must point to a block of memory allocated by `alloc`.
1119-
///
1120-
/// # Examples
1121-
///
1122-
/// Recreate a `Box` which was previously converted to a raw pointer
1123-
/// using [`Box::into_raw_with_allocator`]:
1124-
/// ```
1125-
/// #![feature(allocator_api)]
1126-
///
1127-
/// use std::alloc::System;
1128-
///
1129-
/// let x = Box::new_in(5, System);
1130-
/// let (ptr, alloc) = Box::into_raw_with_allocator(x);
1131-
/// let x = unsafe { Box::from_raw_in(ptr, alloc) };
1132-
/// ```
1133-
/// Manually create a `Box` from scratch by using the system allocator:
1134-
/// ```
1135-
/// #![feature(allocator_api, slice_ptr_get)]
1136-
///
1137-
/// use std::alloc::{Allocator, Layout, System};
1138-
///
1139-
/// unsafe {
1140-
/// let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32;
1141-
/// // In general .write is required to avoid attempting to destruct
1142-
/// // the (uninitialized) previous contents of `ptr`, though for this
1143-
/// // simple example `*ptr = 5` would have worked as well.
1144-
/// ptr.write(5);
1145-
/// let x = Box::from_raw_in(ptr, System);
1146-
/// }
1147-
/// # Ok::<(), std::alloc::AllocError>(())
1148-
/// ```
1149-
///
1150-
/// [memory layout]: self#memory-layout
1151-
#[unstable(feature = "allocator_api", issue = "32838")]
1152-
#[inline]
1153-
pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
1154-
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
1155-
}
1156-
1157-
/// Constructs a box from a `NonNull` pointer in the given allocator.
1158-
///
1159-
/// After calling this function, the `NonNull` pointer is owned by
1160-
/// the resulting `Box`. Specifically, the `Box` destructor will call
1161-
/// the destructor of `T` and free the allocated memory. For this
1162-
/// to be safe, the memory must have been allocated in accordance
1163-
/// with the [memory layout] used by `Box` .
1164-
///
1165-
/// # Safety
1166-
///
1167-
/// This function is unsafe because improper use may lead to
1168-
/// memory problems. For example, a double-free may occur if the
1169-
/// function is called twice on the same raw pointer.
1170-
///
1171-
/// The non-null pointer must point to a block of memory allocated by `alloc`.
1172-
///
1173-
/// # Examples
1174-
///
1175-
/// Recreate a `Box` which was previously converted to a `NonNull` pointer
1176-
/// using [`Box::into_non_null_with_allocator`]:
1177-
/// ```
1178-
/// #![feature(allocator_api, box_vec_non_null)]
1179-
///
1180-
/// use std::alloc::System;
1181-
///
1182-
/// let x = Box::new_in(5, System);
1183-
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
1184-
/// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
1185-
/// ```
1186-
/// Manually create a `Box` from scratch by using the system allocator:
1187-
/// ```
1188-
/// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)]
1189-
///
1190-
/// use std::alloc::{Allocator, Layout, System};
1191-
///
1192-
/// unsafe {
1193-
/// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>();
1194-
/// // In general .write is required to avoid attempting to destruct
1195-
/// // the (uninitialized) previous contents of `non_null`.
1196-
/// non_null.write(5);
1197-
/// let x = Box::from_non_null_in(non_null, System);
1198-
/// }
1199-
/// # Ok::<(), std::alloc::AllocError>(())
1200-
/// ```
1201-
///
1202-
/// [memory layout]: self#memory-layout
1203-
#[unstable(feature = "allocator_api", issue = "32838")]
1204-
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
1205-
#[inline]
1206-
pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
1207-
// SAFETY: guaranteed by the caller.
1208-
unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
1209-
}
12101101

12111102
/// Consumes the `Box`, returning a wrapped raw pointer.
12121103
///
@@ -1322,6 +1213,115 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
13221213
// SAFETY: `Box` is guaranteed to be non-null.
13231214
unsafe { NonNull::new_unchecked(Self::into_raw(b)) }
13241215
}
1216+
}
1217+
1218+
impl<T: ?Sized, A: Allocator> Box<T, A> {
1219+
/// Constructs a box from a raw pointer in the given allocator.
1220+
///
1221+
/// After calling this function, the raw pointer is owned by the
1222+
/// resulting `Box`. Specifically, the `Box` destructor will call
1223+
/// the destructor of `T` and free the allocated memory. For this
1224+
/// to be safe, the memory must have been allocated in accordance
1225+
/// with the [memory layout] used by `Box` .
1226+
///
1227+
/// # Safety
1228+
///
1229+
/// This function is unsafe because improper use may lead to
1230+
/// memory problems. For example, a double-free may occur if the
1231+
/// function is called twice on the same raw pointer.
1232+
///
1233+
/// The raw pointer must point to a block of memory allocated by `alloc`.
1234+
///
1235+
/// # Examples
1236+
///
1237+
/// Recreate a `Box` which was previously converted to a raw pointer
1238+
/// using [`Box::into_raw_with_allocator`]:
1239+
/// ```
1240+
/// #![feature(allocator_api)]
1241+
///
1242+
/// use std::alloc::System;
1243+
///
1244+
/// let x = Box::new_in(5, System);
1245+
/// let (ptr, alloc) = Box::into_raw_with_allocator(x);
1246+
/// let x = unsafe { Box::from_raw_in(ptr, alloc) };
1247+
/// ```
1248+
/// Manually create a `Box` from scratch by using the system allocator:
1249+
/// ```
1250+
/// #![feature(allocator_api, slice_ptr_get)]
1251+
///
1252+
/// use std::alloc::{Allocator, Layout, System};
1253+
///
1254+
/// unsafe {
1255+
/// let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32;
1256+
/// // In general .write is required to avoid attempting to destruct
1257+
/// // the (uninitialized) previous contents of `ptr`, though for this
1258+
/// // simple example `*ptr = 5` would have worked as well.
1259+
/// ptr.write(5);
1260+
/// let x = Box::from_raw_in(ptr, System);
1261+
/// }
1262+
/// # Ok::<(), std::alloc::AllocError>(())
1263+
/// ```
1264+
///
1265+
/// [memory layout]: self#memory-layout
1266+
#[unstable(feature = "allocator_api", issue = "32838")]
1267+
#[inline]
1268+
pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
1269+
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
1270+
}
1271+
1272+
/// Constructs a box from a `NonNull` pointer in the given allocator.
1273+
///
1274+
/// After calling this function, the `NonNull` pointer is owned by
1275+
/// the resulting `Box`. Specifically, the `Box` destructor will call
1276+
/// the destructor of `T` and free the allocated memory. For this
1277+
/// to be safe, the memory must have been allocated in accordance
1278+
/// with the [memory layout] used by `Box` .
1279+
///
1280+
/// # Safety
1281+
///
1282+
/// This function is unsafe because improper use may lead to
1283+
/// memory problems. For example, a double-free may occur if the
1284+
/// function is called twice on the same raw pointer.
1285+
///
1286+
/// The non-null pointer must point to a block of memory allocated by `alloc`.
1287+
///
1288+
/// # Examples
1289+
///
1290+
/// Recreate a `Box` which was previously converted to a `NonNull` pointer
1291+
/// using [`Box::into_non_null_with_allocator`]:
1292+
/// ```
1293+
/// #![feature(allocator_api, box_vec_non_null)]
1294+
///
1295+
/// use std::alloc::System;
1296+
///
1297+
/// let x = Box::new_in(5, System);
1298+
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
1299+
/// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
1300+
/// ```
1301+
/// Manually create a `Box` from scratch by using the system allocator:
1302+
/// ```
1303+
/// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)]
1304+
///
1305+
/// use std::alloc::{Allocator, Layout, System};
1306+
///
1307+
/// unsafe {
1308+
/// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>();
1309+
/// // In general .write is required to avoid attempting to destruct
1310+
/// // the (uninitialized) previous contents of `non_null`.
1311+
/// non_null.write(5);
1312+
/// let x = Box::from_non_null_in(non_null, System);
1313+
/// }
1314+
/// # Ok::<(), std::alloc::AllocError>(())
1315+
/// ```
1316+
///
1317+
/// [memory layout]: self#memory-layout
1318+
#[unstable(feature = "allocator_api", issue = "32838")]
1319+
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
1320+
#[inline]
1321+
pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
1322+
// SAFETY: guaranteed by the caller.
1323+
unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
1324+
}
13251325

13261326
/// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
13271327
///
@@ -1602,7 +1602,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
16021602
where
16031603
A: 'a,
16041604
{
1605-
unsafe { &mut *Box::into_raw(b) }
1605+
let (ptr, alloc) = Box::into_raw_with_allocator(b);
1606+
mem::forget(alloc);
1607+
unsafe { &mut *ptr }
16061608
}
16071609

16081610
/// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then

library/alloc/src/rc.rs

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,30 @@ impl<T: ?Sized> Rc<T> {
13221322
unsafe { Self::from_raw_in(ptr, Global) }
13231323
}
13241324

1325+
/// Consumes the `Rc`, returning the wrapped pointer.
1326+
///
1327+
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1328+
/// [`Rc::from_raw`].
1329+
///
1330+
/// # Examples
1331+
///
1332+
/// ```
1333+
/// use std::rc::Rc;
1334+
///
1335+
/// let x = Rc::new("hello".to_owned());
1336+
/// let x_ptr = Rc::into_raw(x);
1337+
/// assert_eq!(unsafe { &*x_ptr }, "hello");
1338+
/// # // Prevent leaks for Miri.
1339+
/// # drop(unsafe { Rc::from_raw(x_ptr) });
1340+
/// ```
1341+
#[must_use = "losing the pointer will leak memory"]
1342+
#[stable(feature = "rc_raw", since = "1.17.0")]
1343+
#[rustc_never_returns_null_ptr]
1344+
pub fn into_raw(this: Self) -> *const T {
1345+
let this = ManuallyDrop::new(this);
1346+
Self::as_ptr(&*this)
1347+
}
1348+
13251349
/// Increments the strong reference count on the `Rc<T>` associated with the
13261350
/// provided pointer by one.
13271351
///
@@ -1408,30 +1432,6 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
14081432
&this.alloc
14091433
}
14101434

1411-
/// Consumes the `Rc`, returning the wrapped pointer.
1412-
///
1413-
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1414-
/// [`Rc::from_raw`].
1415-
///
1416-
/// # Examples
1417-
///
1418-
/// ```
1419-
/// use std::rc::Rc;
1420-
///
1421-
/// let x = Rc::new("hello".to_owned());
1422-
/// let x_ptr = Rc::into_raw(x);
1423-
/// assert_eq!(unsafe { &*x_ptr }, "hello");
1424-
/// # // Prevent leaks for Miri.
1425-
/// # drop(unsafe { Rc::from_raw(x_ptr) });
1426-
/// ```
1427-
#[must_use = "losing the pointer will leak memory"]
1428-
#[stable(feature = "rc_raw", since = "1.17.0")]
1429-
#[rustc_never_returns_null_ptr]
1430-
pub fn into_raw(this: Self) -> *const T {
1431-
let this = ManuallyDrop::new(this);
1432-
Self::as_ptr(&*this)
1433-
}
1434-
14351435
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
14361436
///
14371437
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -3124,6 +3124,39 @@ impl<T: ?Sized> Weak<T> {
31243124
pub unsafe fn from_raw(ptr: *const T) -> Self {
31253125
unsafe { Self::from_raw_in(ptr, Global) }
31263126
}
3127+
3128+
/// Consumes the `Weak<T>` and turns it into a raw pointer.
3129+
///
3130+
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
3131+
/// one weak reference (the weak count is not modified by this operation). It can be turned
3132+
/// back into the `Weak<T>` with [`from_raw`].
3133+
///
3134+
/// The same restrictions of accessing the target of the pointer as with
3135+
/// [`as_ptr`] apply.
3136+
///
3137+
/// # Examples
3138+
///
3139+
/// ```
3140+
/// use std::rc::{Rc, Weak};
3141+
///
3142+
/// let strong = Rc::new("hello".to_owned());
3143+
/// let weak = Rc::downgrade(&strong);
3144+
/// let raw = weak.into_raw();
3145+
///
3146+
/// assert_eq!(1, Rc::weak_count(&strong));
3147+
/// assert_eq!("hello", unsafe { &*raw });
3148+
///
3149+
/// drop(unsafe { Weak::from_raw(raw) });
3150+
/// assert_eq!(0, Rc::weak_count(&strong));
3151+
/// ```
3152+
///
3153+
/// [`from_raw`]: Weak::from_raw
3154+
/// [`as_ptr`]: Weak::as_ptr
3155+
#[must_use = "losing the pointer will leak memory"]
3156+
#[stable(feature = "weak_into_raw", since = "1.45.0")]
3157+
pub fn into_raw(self) -> *const T {
3158+
mem::ManuallyDrop::new(self).as_ptr()
3159+
}
31273160
}
31283161

31293162
impl<T: ?Sized, A: Allocator> Weak<T, A> {
@@ -3176,39 +3209,6 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
31763209
}
31773210
}
31783211

3179-
/// Consumes the `Weak<T>` and turns it into a raw pointer.
3180-
///
3181-
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
3182-
/// one weak reference (the weak count is not modified by this operation). It can be turned
3183-
/// back into the `Weak<T>` with [`from_raw`].
3184-
///
3185-
/// The same restrictions of accessing the target of the pointer as with
3186-
/// [`as_ptr`] apply.
3187-
///
3188-
/// # Examples
3189-
///
3190-
/// ```
3191-
/// use std::rc::{Rc, Weak};
3192-
///
3193-
/// let strong = Rc::new("hello".to_owned());
3194-
/// let weak = Rc::downgrade(&strong);
3195-
/// let raw = weak.into_raw();
3196-
///
3197-
/// assert_eq!(1, Rc::weak_count(&strong));
3198-
/// assert_eq!("hello", unsafe { &*raw });
3199-
///
3200-
/// drop(unsafe { Weak::from_raw(raw) });
3201-
/// assert_eq!(0, Rc::weak_count(&strong));
3202-
/// ```
3203-
///
3204-
/// [`from_raw`]: Weak::from_raw
3205-
/// [`as_ptr`]: Weak::as_ptr
3206-
#[must_use = "losing the pointer will leak memory"]
3207-
#[stable(feature = "weak_into_raw", since = "1.45.0")]
3208-
pub fn into_raw(self) -> *const T {
3209-
mem::ManuallyDrop::new(self).as_ptr()
3210-
}
3211-
32123212
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
32133213
///
32143214
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of

0 commit comments

Comments
 (0)