Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve from_raw_parts docs #66111

Merged
merged 5 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/liballoc/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ impl String {
/// checked:
///
/// * The memory at `ptr` needs to have been previously allocated by the
/// same allocator the standard library uses.
/// same allocator the standard library uses, with a required alignment of exactly 1.
/// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the correct value.
///
Expand Down
23 changes: 18 additions & 5 deletions src/libcore/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
//! * All pointers (except for the null pointer) are valid for all operations of
//! [size zero][zst].
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
//! be *dereferencable*: the memory range of the given size starting at the pointer must all be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fairly abstract and packed -- can we give an example perhaps?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not really a good way (that I can think of) to do that in the current format -- it would need basically a re-write of this section, I think. And the phrasing is similar to our existing docs for, e.g., ptr::offset.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah; alright -- better to have some docs than none. r=me if you are happy with the current state.

//! within the bounds of a single allocated object. Note that in Rust,
//! every (stack-allocated) variable is considered a separate allocated object.
//! * All accesses performed by functions in this module are *non-atomic* in the sense
//! of [atomic operations] used to synchronize between threads. This means it is
//! undefined behavior to perform two concurrent accesses to the same location from different
Expand Down Expand Up @@ -221,10 +225,15 @@ pub(crate) struct FatPtr<T> {
pub(crate) len: usize,
}

/// Forms a slice from a pointer and a length.
/// Forms a raw slice from a pointer and a length.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
/// This function is safe, but actually using the return value is unsafe.
/// See the documentation of [`from_raw_parts`] for slice safety requirements.
///
/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
///
/// # Examples
///
/// ```rust
Expand All @@ -243,12 +252,16 @@ pub fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
unsafe { Repr { raw: FatPtr { data, len } }.rust }
}

/// Performs the same functionality as [`from_raw_parts`], except that a
/// mutable slice is returned.
/// Performs the same functionality as [`slice_from_raw_parts`], except that a
/// raw mutable slice is returned, as opposed to a raw immutable slice.
///
/// See the documentation of [`from_raw_parts`] for more details.
/// See the documentation of [`slice_from_raw_parts`] for more details.
///
/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
/// This function is safe, but actually using the return value is unsafe.
/// See the documentation of [`from_raw_parts_mut`] for slice safety requirements.
///
/// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html
/// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html
#[inline]
#[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")]
pub fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
Expand Down
60 changes: 42 additions & 18 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5272,18 +5272,24 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
///
/// # Safety
///
/// This function is unsafe as there is no guarantee that the given pointer is
/// valid for `len` elements, nor whether the lifetime inferred is a suitable
/// lifetime for the returned slice.
/// Behavior is undefined if any of the following conditions are violated:
///
/// `data` must be non-null and aligned, even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references
/// (including slices of any length) being aligned and non-null to distinguish
/// them from other data. You can obtain a pointer that is usable as `data`
/// for zero-length slices using [`NonNull::dangling()`].
/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
/// and it must be properly aligned. This means in particular:
///
/// The total size of the slice must be no larger than `isize::MAX` **bytes**
/// in memory. See the safety documentation of [`pointer::offset`].
/// * The entire memory range of this slice must be contained within a single allocated object!
/// Slices can never span across multiple allocated objects.
/// * `data` must be non-null and aligned even for zero-length slices. One
/// reason for this is that enum layout optimizations may rely on references
/// (including slices of any length) being aligned and non-null to distinguish
/// them from other data. You can obtain a pointer that is usable as `data`
/// for zero-length slices using [`NonNull::dangling()`].
///
/// * The memory referenced by the returned slice must not be mutated for the duration
/// of lifetime `'a`, except inside an `UnsafeCell`.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
/// See the safety documentation of [`pointer::offset`].
///
/// # Caveat
///
Expand All @@ -5305,35 +5311,53 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
/// assert_eq!(slice[0], 42);
/// ```
///
/// [valid]: ../../std/ptr/index.html#safety
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
"attempt to create slice covering half the address space");
"attempt to create slice covering at least half the address space");
&*ptr::slice_from_raw_parts(data, len)
}

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

Expand Down