fix for undefined behavior in <[T]>::copy_within method #85675
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
<[T]>::copy_within()
currently contains undefined behavior according to the Stacked Borrows model. This PR brings a fix to restore its soundness.To help understand where the UB comes from, consider the following code snippet from the original implementation of
copy_within
before the fix:The arguments to
ptr::copy
are evaluated from left to right.self.as_ptr()
creates an immutable reference (which is tagged as SharedReadOnly by Stacked Borrows) to the array and derives a valid*const
pointer from it. When jumping to the next argument,self.as_mut_ptr()
creates a mutable reference (tagged as Unique) to the array, which invalidates the existing SharedReadOnly reference and any pointers derived from it. The invalidated*const
pointer (the first argument toptr::copy
) is then used after the fact whenptr::copy
is called, which triggers the undefined behavior.The fix is to obtain only one mutable reference (tagged Unique) at the start, then cast it to a mutable pointer (tagged SharedReadWrite), for which both of the pointer arguments to
ptr::copy
can be safely derived without invalidating either pointer, like so: