Skip to content

Commit b94a2f9

Browse files
authored
Rollup merge of rust-lang#66111 - RalfJung:from_raw_parts, r=Centril
improve from_raw_parts docs Triggered by rust-lang/rfcs#2806. Hopefully this helps clarify that joining slices across allocations is not possible in Rust currently. r? @Centril
2 parents 64b2f5c + 11a48a0 commit b94a2f9

File tree

3 files changed

+61
-24
lines changed

3 files changed

+61
-24
lines changed

src/liballoc/string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ impl String {
687687
/// checked:
688688
///
689689
/// * The memory at `ptr` needs to have been previously allocated by the
690-
/// same allocator the standard library uses.
690+
/// same allocator the standard library uses, with a required alignment of exactly 1.
691691
/// * `length` needs to be less than or equal to `capacity`.
692692
/// * `capacity` needs to be the correct value.
693693
///

src/libcore/ptr/mod.rs

+18-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
1919
//! * All pointers (except for the null pointer) are valid for all operations of
2020
//! [size zero][zst].
21+
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
22+
//! be *dereferencable*: the memory range of the given size starting at the pointer must all be
23+
//! within the bounds of a single allocated object. Note that in Rust,
24+
//! every (stack-allocated) variable is considered a separate allocated object.
2125
//! * All accesses performed by functions in this module are *non-atomic* in the sense
2226
//! of [atomic operations] used to synchronize between threads. This means it is
2327
//! undefined behavior to perform two concurrent accesses to the same location from different
@@ -221,10 +225,15 @@ pub(crate) struct FatPtr<T> {
221225
pub(crate) len: usize,
222226
}
223227

224-
/// Forms a slice from a pointer and a length.
228+
/// Forms a raw slice from a pointer and a length.
225229
///
226230
/// The `len` argument is the number of **elements**, not the number of bytes.
227231
///
232+
/// This function is safe, but actually using the return value is unsafe.
233+
/// See the documentation of [`from_raw_parts`] for slice safety requirements.
234+
///
235+
/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
236+
///
228237
/// # Examples
229238
///
230239
/// ```rust
@@ -243,12 +252,16 @@ pub fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
243252
unsafe { Repr { raw: FatPtr { data, len } }.rust }
244253
}
245254

246-
/// Performs the same functionality as [`from_raw_parts`], except that a
247-
/// mutable slice is returned.
255+
/// Performs the same functionality as [`slice_from_raw_parts`], except that a
256+
/// raw mutable slice is returned, as opposed to a raw immutable slice.
248257
///
249-
/// See the documentation of [`from_raw_parts`] for more details.
258+
/// See the documentation of [`slice_from_raw_parts`] for more details.
250259
///
251-
/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
260+
/// This function is safe, but actually using the return value is unsafe.
261+
/// See the documentation of [`from_raw_parts_mut`] for slice safety requirements.
262+
///
263+
/// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html
264+
/// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html
252265
#[inline]
253266
#[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")]
254267
pub fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {

src/libcore/slice/mod.rs

+42-18
Original file line numberDiff line numberDiff line change
@@ -5272,18 +5272,24 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
52725272
///
52735273
/// # Safety
52745274
///
5275-
/// This function is unsafe as there is no guarantee that the given pointer is
5276-
/// valid for `len` elements, nor whether the lifetime inferred is a suitable
5277-
/// lifetime for the returned slice.
5275+
/// Behavior is undefined if any of the following conditions are violated:
52785276
///
5279-
/// `data` must be non-null and aligned, even for zero-length slices. One
5280-
/// reason for this is that enum layout optimizations may rely on references
5281-
/// (including slices of any length) being aligned and non-null to distinguish
5282-
/// them from other data. You can obtain a pointer that is usable as `data`
5283-
/// for zero-length slices using [`NonNull::dangling()`].
5277+
/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
5278+
/// and it must be properly aligned. This means in particular:
52845279
///
5285-
/// The total size of the slice must be no larger than `isize::MAX` **bytes**
5286-
/// in memory. See the safety documentation of [`pointer::offset`].
5280+
/// * The entire memory range of this slice must be contained within a single allocated object!
5281+
/// Slices can never span across multiple allocated objects.
5282+
/// * `data` must be non-null and aligned even for zero-length slices. One
5283+
/// reason for this is that enum layout optimizations may rely on references
5284+
/// (including slices of any length) being aligned and non-null to distinguish
5285+
/// them from other data. You can obtain a pointer that is usable as `data`
5286+
/// for zero-length slices using [`NonNull::dangling()`].
5287+
///
5288+
/// * The memory referenced by the returned slice must not be mutated for the duration
5289+
/// of lifetime `'a`, except inside an `UnsafeCell`.
5290+
///
5291+
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
5292+
/// See the safety documentation of [`pointer::offset`].
52875293
///
52885294
/// # Caveat
52895295
///
@@ -5305,35 +5311,53 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
53055311
/// assert_eq!(slice[0], 42);
53065312
/// ```
53075313
///
5314+
/// [valid]: ../../std/ptr/index.html#safety
53085315
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
53095316
/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
53105317
#[inline]
53115318
#[stable(feature = "rust1", since = "1.0.0")]
53125319
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
53135320
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
53145321
debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
5315-
"attempt to create slice covering half the address space");
5322+
"attempt to create slice covering at least half the address space");
53165323
&*ptr::slice_from_raw_parts(data, len)
53175324
}
53185325

53195326
/// Performs the same functionality as [`from_raw_parts`], except that a
53205327
/// mutable slice is returned.
53215328
///
5322-
/// This function is unsafe for the same reasons as [`from_raw_parts`], as well
5323-
/// as not being able to provide a non-aliasing guarantee of the returned
5324-
/// mutable slice. `data` must be non-null and aligned even for zero-length
5325-
/// slices as with [`from_raw_parts`]. The total size of the slice must be no
5326-
/// larger than `isize::MAX` **bytes** in memory.
5329+
/// # Safety
5330+
///
5331+
/// Behavior is undefined if any of the following conditions are violated:
5332+
///
5333+
/// * `data` must be [valid] for writes for `len * mem::size_of::<T>()` many bytes,
5334+
/// and it must be properly aligned. This means in particular:
53275335
///
5328-
/// See the documentation of [`from_raw_parts`] for more details.
5336+
/// * The entire memory range of this slice must be contained within a single allocated object!
5337+
/// Slices can never span across multiple allocated objects.
5338+
/// * `data` must be non-null and aligned even for zero-length slices. One
5339+
/// reason for this is that enum layout optimizations may rely on references
5340+
/// (including slices of any length) being aligned and non-null to distinguish
5341+
/// them from other data. You can obtain a pointer that is usable as `data`
5342+
/// for zero-length slices using [`NonNull::dangling()`].
53295343
///
5344+
/// * The memory referenced by the returned slice must not be accessed through any other pointer
5345+
/// (not derived from the return value) for the duration of lifetime `'a`.
5346+
/// Both read and write accesses are forbidden.
5347+
///
5348+
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
5349+
/// See the safety documentation of [`pointer::offset`].
5350+
///
5351+
/// [valid]: ../../std/ptr/index.html#safety
5352+
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
5353+
/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
53305354
/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
53315355
#[inline]
53325356
#[stable(feature = "rust1", since = "1.0.0")]
53335357
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
53345358
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
53355359
debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
5336-
"attempt to create slice covering half the address space");
5360+
"attempt to create slice covering at least half the address space");
53375361
&mut *ptr::slice_from_raw_parts_mut(data, len)
53385362
}
53395363

0 commit comments

Comments
 (0)