Skip to content

ptr::copy_nonoverlapping is not memcpy #113347

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

Closed
Closed
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
26 changes: 9 additions & 17 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2574,14 +2574,9 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
///
/// For regions of memory which might overlap, use [`copy`] instead.
///
/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
/// with the argument order swapped.
///
/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
/// requirements of `T`. The initialization state is preserved exactly.
///
/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
Expand All @@ -2603,6 +2598,8 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
///
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
/// `0`, the pointers must be non-null and properly aligned.
/// In this case, the pointers may share the same address, as
/// a region of 0 bytes does not overlap with a region of 0 bytes.
///
/// [`read`]: crate::ptr::read
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
Expand Down Expand Up @@ -2684,18 +2681,15 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
/// and destination may overlap.
///
/// If the source and destination will *never* overlap,
/// [`copy_nonoverlapping`] can be used instead.
///
/// `copy` is semantically equivalent to C's [`memmove`], but with the argument
/// order swapped. Copying takes place as if the bytes were copied from `src`
/// to a temporary array and then copied from the array to `dst`.
/// `copy` may temporarily use additional space to copy bytes from `src` into an array, before
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't it just copy forwards/backwards depending on which region is "lower"? I don't think you ever need a temporary array?

Copy link
Member Author

Choose a reason for hiding this comment

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

arguably a register is in fact a "temporary array", but you're right, I think.

/// copying them to `dst`. This lets `copy` correctly handle overlapping locations.
/// If `src` and `dst` *never* overlap, [`copy_nonoverlapping`] may be used to avoid overhead.
/// Note that in many cases, this additional overhead can be removed or reduced by the compiler,
/// as this is an "intrinsic function" implemented directly through the compiler.
///
/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
/// requirements of `T`. The initialization state is preserved exactly.
///
/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
Expand Down Expand Up @@ -2771,10 +2765,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
/// `val`.
///
/// `write_bytes` is similar to C's [`memset`], but sets `count *
/// size_of::<T>()` bytes to `val`.
///
/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
/// Note that this means that if `T` is multiple bytes, each byte is set to the same value,
/// which may be interpreted to mean a very different value when interpreted as `T`.
///
/// # Safety
///
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ impl<T> MaybeUninit<T> {
/// // Initialize `buf`:
/// unsafe { initialize_buffer(buf.as_mut_ptr()); }
/// // Now we know that `buf` has been initialized, so we could `.assume_init()` it.
/// // However, using `.assume_init()` may trigger a `memcpy` of the 1024 bytes.
/// // However, using `.assume_init()` may trigger a copy of the 1024 bytes.
/// // To assert our buffer has been initialized without copying it, we upgrade
/// // the `&mut MaybeUninit<[u8; 1024]>` to a `&mut [u8; 1024]`:
/// let buf: &mut [u8; 1024] = unsafe {
Expand Down
3 changes: 1 addition & 2 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,8 +1449,7 @@ impl<T: ?Sized> *mut T {
unsafe { write(self, val) }
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
/// bytes of memory starting at `self` to `val`.
/// Sets `count * size_of::<T>()` bytes starting at `self` to `val`.
///
/// See [`ptr::write_bytes`] for safety concerns and examples.
///
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3531,7 +3531,7 @@ impl<T> [T] {
self.spec_clone_from(src);
}

/// Copies all elements from `src` into `self`, using a memcpy.
/// Copies all elements from `src` into `self`, using [`ptr::copy_nonoverlapping`].
///
/// The length of `src` must be the same as `self`.
///
Expand Down Expand Up @@ -3617,7 +3617,7 @@ impl<T> [T] {
}

/// Copies elements from one part of the slice to another part of itself,
/// using a memmove.
/// using [`ptr::copy`].
///
/// `src` is the range within `self` to copy from. `dest` is the starting
/// index of the range within `self` to copy to, which will have the same
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/slice/rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use crate::ptr;
/// only once.
///
/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to
/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove`
/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, [`ptr::copy`]
/// is applied to the others, and the ones on the buffer are moved back into the hole on the
/// opposite side of where they originated.
///
Expand Down