Skip to content

Commit ba3c3d9

Browse files
Rollup merge of rust-lang#106950 - the8472:fix-splice-miri, r=cuviper
Don't do pointer arithmetic on pointers to deallocated memory vec::Splice can invalidate the slice::Iter inside vec::Drain. So we replace them with dangling pointers which, unlike ones to deallocated memory, are allowed. Fixes miri test failures. Fixes rust-lang/miri#2759
2 parents b9ce633 + 2d54b7c commit ba3c3d9

File tree

3 files changed

+15
-3
lines changed

3 files changed

+15
-3
lines changed

library/alloc/src/vec/drain.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
223223
}
224224

225225
// as_slice() must only be called when iter.len() is > 0 because
226-
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
227-
// the iterator's internal pointers. Creating a reference to deallocated memory
228-
// is invalid even when it is zero-length
226+
// it also gets touched by vec::Splice which may turn it into a dangling pointer
227+
// which would make it and the vec pointer point to different allocations which would
228+
// lead to invalid pointer arithmetic below.
229229
let drop_ptr = iter.as_slice().as_ptr();
230230

231231
unsafe {

library/alloc/src/vec/splice.rs

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
5454
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
5555
fn drop(&mut self) {
5656
self.drain.by_ref().for_each(drop);
57+
// At this point draining is done and the only remaining tasks are splicing
58+
// and moving things into the final place.
59+
// Which means we can replace the slice::Iter with pointers that won't point to deallocated
60+
// memory, so that Drain::drop is still allowed to call iter.len(), otherwise it would break
61+
// the ptr.sub_ptr contract.
62+
self.drain.iter = (&[]).iter();
5763

5864
unsafe {
5965
if self.drain.tail_len == 0 {

src/tools/miri/tests/pass/vec.rs

+6
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ fn reverse() {
162162
assert!(v[0].0 == 49);
163163
}
164164

165+
fn miri_issue_2759() {
166+
let mut input = "1".to_string();
167+
input.replace_range(0..0, "0");
168+
}
169+
165170
fn main() {
166171
assert_eq!(vec_reallocate().len(), 5);
167172

@@ -191,4 +196,5 @@ fn main() {
191196
swap();
192197
swap_remove();
193198
reverse();
199+
miri_issue_2759();
194200
}

0 commit comments

Comments
 (0)