Skip to content

Commit d32c320

Browse files
committed
Auto merge of #79814 - lcnr:deque-f, r=Mark-Simulacrum
fix soundness issue in `make_contiguous` fixes #79808
2 parents 80cc2ec + 4fb9f1d commit d32c320

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

library/alloc/src/collections/vec_deque/mod.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,8 @@ impl<T> VecDeque<T> {
14691469

14701470
#[inline]
14711471
fn is_contiguous(&self) -> bool {
1472+
// FIXME: Should we consider `head == 0` to mean
1473+
// that `self` is contiguous?
14721474
self.tail <= self.head
14731475
}
14741476

@@ -2198,7 +2200,7 @@ impl<T> VecDeque<T> {
21982200
if self.is_contiguous() {
21992201
let tail = self.tail;
22002202
let head = self.head;
2201-
return unsafe { &mut self.buffer_as_mut_slice()[tail..head] };
2203+
return unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 };
22022204
}
22032205

22042206
let buf = self.buf.ptr();
@@ -2224,7 +2226,13 @@ impl<T> VecDeque<T> {
22242226
self.tail = 0;
22252227
self.head = len;
22262228
}
2227-
} else if free >= self.head {
2229+
} else if free > self.head {
2230+
// FIXME: We currently do not consider ....ABCDEFGH
2231+
// to be contiguous because `head` would be `0` in this
2232+
// case. While we probably want to change this it
2233+
// isn't trivial as a few places expect `is_contiguous`
2234+
// to mean that we can just slice using `buf[tail..head]`.
2235+
22282236
// there is enough free space to copy the head in one go,
22292237
// this means that we first shift the tail forwards, and then
22302238
// copy the head to the correct position.
@@ -2238,7 +2246,7 @@ impl<T> VecDeque<T> {
22382246
// ...ABCDEFGH.
22392247

22402248
self.tail = self.head;
2241-
self.head = self.tail + len;
2249+
self.head = self.wrap_add(self.tail, len);
22422250
}
22432251
} else {
22442252
// free is smaller than both head and tail,
@@ -2278,7 +2286,7 @@ impl<T> VecDeque<T> {
22782286

22792287
let tail = self.tail;
22802288
let head = self.head;
2281-
unsafe { &mut self.buffer_as_mut_slice()[tail..head] }
2289+
unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 }
22822290
}
22832291

22842292
/// Rotates the double-ended queue `mid` places to the left.
@@ -2839,7 +2847,7 @@ impl<T> From<VecDeque<T>> for Vec<T> {
28392847
let len = other.len();
28402848
let cap = other.cap();
28412849

2842-
if other.head != 0 {
2850+
if other.tail != 0 {
28432851
ptr::copy(buf.add(other.tail), buf, len);
28442852
}
28452853
Vec::from_raw_parts(buf, len, cap)

library/alloc/src/collections/vec_deque/tests.rs

+14
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ fn make_contiguous_small_free() {
210210
);
211211
}
212212

213+
#[test]
214+
fn make_contiguous_head_to_end() {
215+
let mut dq = VecDeque::with_capacity(3);
216+
dq.push_front('B');
217+
dq.push_front('A');
218+
dq.push_back('C');
219+
dq.make_contiguous();
220+
let expected_tail = 0;
221+
let expected_head = 3;
222+
assert_eq!(expected_tail, dq.tail);
223+
assert_eq!(expected_head, dq.head);
224+
assert_eq!((&['A', 'B', 'C'] as &[_], &[] as &[_]), dq.as_slices());
225+
}
226+
213227
#[test]
214228
fn test_remove() {
215229
// This test checks that every single combination of tail position, length, and

0 commit comments

Comments
 (0)