From 527934d15cfbcfa2f92c63acd390b935143d2c05 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 8 Dec 2020 10:34:31 +0100 Subject: [PATCH] fix unsoundness in `make_contiguous` --- library/alloc/src/collections/vec_deque.rs | 18 +++++++++++++----- .../alloc/src/collections/vec_deque/tests.rs | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 22b02a4f849b6..c0a3ca6a582bb 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -1507,6 +1507,8 @@ impl VecDeque { #[inline] fn is_contiguous(&self) -> bool { + // FIXME: Should we consider `head == 0` to mean + // that `self` is contiguous? self.tail <= self.head } @@ -2236,7 +2238,7 @@ impl VecDeque { if self.is_contiguous() { let tail = self.tail; let head = self.head; - return unsafe { &mut self.buffer_as_mut_slice()[tail..head] }; + return unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 }; } let buf = self.buf.ptr(); @@ -2262,7 +2264,13 @@ impl VecDeque { self.tail = 0; self.head = len; } - } else if free >= self.head { + } else if free > self.head { + // FIXME: We currently do not consider ....ABCDEFGH + // to be contiguous because `head` would be `0` in this + // case. While we probably want to change this it + // isn't trivial as a few places expect `is_contiguous` + // to mean that we can just slice using `buf[tail..head]`. + // there is enough free space to copy the head in one go, // this means that we first shift the tail forwards, and then // copy the head to the correct position. @@ -2276,7 +2284,7 @@ impl VecDeque { // ...ABCDEFGH. self.tail = self.head; - self.head = self.tail + len; + self.head = self.wrap_add(self.tail, len); } } else { // free is smaller than both head and tail, @@ -2316,7 +2324,7 @@ impl VecDeque { let tail = self.tail; let head = self.head; - unsafe { &mut self.buffer_as_mut_slice()[tail..head] } + unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 } } /// Rotates the double-ended queue `mid` places to the left. @@ -3282,7 +3290,7 @@ impl From> for Vec { let len = other.len(); let cap = other.cap(); - if other.head != 0 { + if other.tail != 0 { ptr::copy(buf.add(other.tail), buf, len); } Vec::from_raw_parts(buf, len, cap) diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index d74f91c752c04..21f52af056b2a 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -210,6 +210,20 @@ fn make_contiguous_small_free() { ); } +#[test] +fn make_contiguous_head_to_end() { + let mut dq = VecDeque::with_capacity(3); + dq.push_front('B'); + dq.push_front('A'); + dq.push_back('C'); + dq.make_contiguous(); + let expected_tail = 0; + let expected_head = 3; + assert_eq!(expected_tail, dq.tail); + assert_eq!(expected_head, dq.head); + assert_eq!((&['A', 'B', 'C'] as &[_], &[] as &[_]), dq.as_slices()); +} + #[test] fn test_remove() { // This test checks that every single combination of tail position, length, and