Skip to content

Commit

Permalink
Rollup merge of #92097 - saethlin:split-without-deref, r=the8472
Browse files Browse the repository at this point in the history
Implement split_at_spare_mut without Deref to a slice so that the spare slice is valid

~I'm not sure I understand what's going on here correctly. And I'm pretty sure this safety comment needs to be changed. I'm just referring to the same thing that `as_mut_ptr_range` does.~ (Thanks `@RalfJung` for the guidance and clearing things up)

I tried to run https://github.com/rust-lang/miri-test-libstd on alloc with -Zmiri-track-raw-pointers, and got a failure on the test `vec::test_extend_from_within`.

I minimized the test failure into this program:
```rust
#![feature(vec_split_at_spare)]
fn main() {
    Vec::<i32>::with_capacity(1).split_at_spare_mut();
}
```

The problem is that the existing implementation is actually getting a pointer range where both pointers are derived from the initialized region of the Vec's allocation, but we need the second one to be valid for the region between len and capacity. (thanks Ralf for clearing this up)
  • Loading branch information
matthiaskrgr authored Jan 1, 2022
2 parents 5a5c928 + 777c853 commit a6e4d68
Showing 1 changed file with 7 additions and 2 deletions.
9 changes: 7 additions & 2 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2141,12 +2141,17 @@ impl<T, A: Allocator> Vec<T, A> {
unsafe fn split_at_spare_mut_with_len(
&mut self,
) -> (&mut [T], &mut [MaybeUninit<T>], &mut usize) {
let Range { start: ptr, end: spare_ptr } = self.as_mut_ptr_range();
let ptr = self.as_mut_ptr();
// SAFETY:
// - `ptr` is guaranteed to be valid for `self.len` elements
// - but the allocation extends out to `self.buf.capacity()` elements, possibly
// uninitialized
let spare_ptr = unsafe { ptr.add(self.len) };
let spare_ptr = spare_ptr.cast::<MaybeUninit<T>>();
let spare_len = self.buf.capacity() - self.len;

// SAFETY:
// - `ptr` is guaranteed to be valid for `len` elements
// - `ptr` is guaranteed to be valid for `self.len` elements
// - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized`
unsafe {
let initialized = slice::from_raw_parts_mut(ptr, self.len);
Expand Down

0 comments on commit a6e4d68

Please sign in to comment.