Skip to content

Commit 08c3444

Browse files
committed
avoid violating slice::from_raw_parts safety contract in Vec::extract_if
The implementation of the `Vec::extract_if` iterator violates the safety contract adverized by `slice::from_raw_parts` by always constructing a mutable slice for the entire length of the vector even though that span of memory can contain holes from items already drained. The safety contract of `slice::from_raw_parts` requires that all elements must be properly initialized. As an example we can look at the following code: ```rust let mut v = vec![Box::new(0u64), Box::new(1u64)]; for item in v.extract_if(.., |x| **x == 0) { drop(item); } ``` In the second iteration a `&mut [Box<u64>]` slice of length 2 will be constructed. The first slot of the slice contains the bitpattern of an already deallocated box, which is invalid. This fixes the issue by only creating references to valid items and using pointer manipulation for the rest. I have also taken the liberty to remove the big `unsafe` blocks in place of targetted ones with a SAFETY comment. The approach closely mirrors the implementation of `Vec::retain_mut`. Signed-off-by: Petros Angelatos <[email protected]>
1 parent dca1a23 commit 08c3444

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

tests/pass/vec.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,15 @@ fn miri_issue_2759() {
169169
input.replace_range(0..0, "0");
170170
}
171171

172+
/// This was skirting the edge of UB, let's make sure it remains on the sound side.
173+
/// Context: <https://github.com/rust-lang/rust/pull/141032>.
174+
fn extract_if() {
175+
let mut v = vec![Box::new(0u64), Box::new(1u64)];
176+
for item in v.extract_if(.., |x| **x == 0) {
177+
drop(item);
178+
}
179+
}
180+
172181
fn main() {
173182
assert_eq!(vec_reallocate().len(), 5);
174183

@@ -199,4 +208,5 @@ fn main() {
199208
swap_remove();
200209
reverse();
201210
miri_issue_2759();
211+
extract_if();
202212
}

0 commit comments

Comments
 (0)