Skip to content

Commit 3fc74ec

Browse files
authored
Rollup merge of #141032 - petrosagg:extract-if-ub, r=joboet
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`. **Note to reviewers:** The diff is easier to follow with whitespace hidden.
2 parents 2026276 + 08c3444 commit 3fc74ec

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)