Skip to content

Commit 15d4cc6

Browse files
committed
update usage of Vec::set_len
In the time since this code was originally written, an update to the Vec docs clarified the rules of safety for Vec::set_len and require that the newly-accessible elements are already initialized. rust-lang/rust#56425
1 parent 340d08d commit 15d4cc6

File tree

1 file changed

+34
-8
lines changed

1 file changed

+34
-8
lines changed

lib.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -451,22 +451,48 @@ mod unsafe_impls {
451451
);
452452

453453
out.clear();
454-
out.reserve_exact(vec.len());
454+
out.reserve_exact(inv.0.len());
455455

456456
//------------------------------------------------
457457
// You are now entering a PANIC FREE ZONE
458458

459-
// Make a bunch of uninitialized elements indexable.
460-
unsafe { out.set_len(vec.len()); }
461-
462-
// a perm holds indices into the data vec, so the inverse holds indices into `out`.
463-
for (vec_i, &out_i) in inv.0.iter().enumerate() {
464-
let tmp = unsafe { ptr::read(&vec[vec_i]) };
465-
unsafe { ptr::write(&mut out[out_i], tmp) };
459+
{ // scope ptrs so we can reason about them
460+
let vec_ptr = vec.as_ptr();
461+
let out_ptr = out.as_mut_ptr();
462+
463+
// a perm holds indices into the data vec, so the inverse holds indices into `out`.
464+
for (vec_i, &out_i) in inv.0.iter().enumerate() {
465+
// SAFETY:
466+
//
467+
// * vec_i < vec.len() because:
468+
// * vec_i comes from the standard library implementation of `impl Iterator for std::iter::Enumerate`,
469+
// and is thus guaranteed to be `< inv.0.len()`.
470+
// * We asserted earlier that `inv.0.len() == vec.len()`.
471+
//
472+
// * vec[vec_i] will not be double-dropped, because:
473+
// * we perform `vec.set_len(0)` after this loop.
474+
// * we cannot possibly panic before this occurs.
475+
let value = unsafe { vec_ptr.offset(vec_i as isize).read() };
476+
477+
// SAFETY:
478+
//
479+
// * out_i < out.capacity() because:
480+
// * A privacy-protected invariant of PermVec guarantees that `out_i < inv.0.len()`.
481+
// * We called `Vec::reserve_exact` to ensure that `inv.0.len() <= out.capacity()`.
482+
let dest_ptr = unsafe { out_ptr.offset(out_i as isize) };
483+
unsafe { dest_ptr.write(value) };
484+
}
466485
}
467486

468487
// Don't drop the original items, but do allow the original
469488
// vec to fall out of scope so the memory can be freed.
489+
490+
// SAFETY:
491+
//
492+
// * All elements in out[0..vec.len()] are initialized because:
493+
// * A privacy-protected invariant of PermVec guarantees that, in the above `for` loop,
494+
// every index from 0..vec.len() will have appeared exactly once as `out_i`.
495+
unsafe { out.set_len(vec.len()); }
470496
unsafe { vec.set_len(0); }
471497

472498
// Thank you for flying with us. You may now PANIC!

0 commit comments

Comments
 (0)