Skip to content

Commit 2dbc8eb

Browse files
committed
Update safety comments, make split_at_mut unsafe
`&mut [T]` implies validity which automatically makes `ptr::add` ok within its bounds. But `*mut [T]` does not. Since we still want the benefits of in-bounds pointer arithmetic `split_at_must` must require the caller to pass valid pointers and therefore it is `unsafe`.
1 parent a8f049b commit 2dbc8eb

File tree

1 file changed

+34
-22
lines changed

1 file changed

+34
-22
lines changed

Diff for: core/src/ptr/mut_ptr.rs

+34-22
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,22 @@ impl<T> *mut [T] {
13661366
///
13671367
/// Panics if `mid > len`.
13681368
///
1369+
/// # Safety
1370+
///
1371+
/// `mid` must be [in-bounds] of the underlying [allocated object].
1372+
/// Which means `self` must be dereferenceable and span a single allocation
1373+
/// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
1374+
/// requirements is *[undefined behavior]* even if the resulting pointers are not used.
1375+
///
1376+
/// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the
1377+
/// safety requirements of this method are the same as for [`split_at_mut_unchecked`].
1378+
/// The explicit bounds check is only as useful as `len` is correct.
1379+
///
1380+
/// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked
1381+
/// [in-bounds]: #method.add
1382+
/// [allocated object]: crate::ptr#allocated-object
1383+
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1384+
///
13691385
/// # Examples
13701386
///
13711387
/// ```
@@ -1374,19 +1390,19 @@ impl<T> *mut [T] {
13741390
///
13751391
/// let mut v = [1, 0, 3, 0, 5, 6];
13761392
/// let ptr = &mut v as *mut [_];
1377-
/// let (left, right) = ptr.split_at_mut(2);
13781393
/// unsafe {
1394+
/// let (left, right) = ptr.split_at_mut(2);
13791395
/// assert_eq!(&*left, [1, 0]);
13801396
/// assert_eq!(&*right, [3, 0, 5, 6]);
13811397
/// }
13821398
/// ```
13831399
#[inline(always)]
13841400
#[track_caller]
13851401
#[unstable(feature = "raw_slice_split", issue = "95595")]
1386-
pub fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) {
1402+
pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) {
13871403
assert!(mid <= self.len());
1388-
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
1389-
// fulfills the requirements of `from_raw_parts_mut`.
1404+
// SAFETY: The assert above is only a safety-net as long as `self.len()` is correct
1405+
// The actual safety requirements of this function are the same as for `split_at_mut_unchecked`
13901406
unsafe { self.split_at_mut_unchecked(mid) }
13911407
}
13921408

@@ -1396,16 +1412,15 @@ impl<T> *mut [T] {
13961412
/// the index `mid` itself) and the second will contain all
13971413
/// indices from `[mid, len)` (excluding the index `len` itself).
13981414
///
1399-
/// For a safe alternative see [`split_at_mut`].
1400-
///
1401-
/// [`split_at_mut`]: #method.split_at_mut
1402-
///
14031415
/// # Safety
14041416
///
1405-
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
1406-
/// even if the resulting reference is not used. The caller has to ensure that
1407-
/// `0 <= mid <= self.len()`.
1417+
/// `mid` must be [in-bounds] of the underlying [allocated object].
1418+
/// Which means `self` must be dereferenceable and span a single allocation
1419+
/// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
1420+
/// requirements is *[undefined behavior]* even if the resulting pointers are not used.
14081421
///
1422+
/// [in-bounds]: #method.add
1423+
/// [out-of-bounds index]: #method.add
14091424
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
14101425
///
14111426
/// # Examples
@@ -1431,16 +1446,12 @@ impl<T> *mut [T] {
14311446
let len = self.len();
14321447
let ptr = self.as_mut_ptr();
14331448

1434-
// SAFETY: Caller has to check that `0 <= mid <= self.len()`.
1435-
//
1436-
// `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference
1437-
// is fine.
1438-
unsafe {
1439-
(
1440-
crate::ptr::slice_from_raw_parts_mut(ptr, mid),
1441-
crate::ptr::slice_from_raw_parts_mut(ptr.add(mid), len - mid),
1442-
)
1443-
}
1449+
// SAFETY: Caller must pass a valid pointer and an index that is in-bounds.
1450+
let tail = unsafe { ptr.add(mid) };
1451+
(
1452+
crate::ptr::slice_from_raw_parts_mut(ptr, mid),
1453+
crate::ptr::slice_from_raw_parts_mut(tail, len - mid),
1454+
)
14441455
}
14451456

14461457
/// Returns a raw pointer to the slice's buffer.
@@ -1466,9 +1477,10 @@ impl<T> *mut [T] {
14661477
/// Returns a raw pointer to an element or subslice, without doing bounds
14671478
/// checking.
14681479
///
1469-
/// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
1480+
/// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable
14701481
/// is *[undefined behavior]* even if the resulting pointer is not used.
14711482
///
1483+
/// [out-of-bounds index]: #method.add
14721484
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
14731485
///
14741486
/// # Examples

0 commit comments

Comments
 (0)