rust-lang/rust

seg fault pushing on either side of a VecDeque

Closed this issue · 4 comments

I've been seeing lots of bad behavior trying to use VecDeque. I've boiled it down to a relatively simple example which shows some of the bad behavior I was seeing and additionally seg faults.

This was with:
rustc 1.20.0 (f3d6973 2017-08-27)
binary: rustc
commit-hash: f3d6973
commit-date: 2017-08-27
host: x86_64-apple-darwin
release: 1.20.0
LLVM version: 4.0
and also rust 1.19

The output I expect to see is:

old packet = 00 88 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 00 37 03 80 45 14 00 14 00 15 00 17
pushing D9 58 FB A8
new packet = 00 88 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 00 37 03 80 45 14 00 14 00 15 00 17 D9 58 FB A8

The output I get is:

old packet = 00 88 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 00 37 03 80 45 14 00 14 00 15 00 17
pushing D9 58 FB A8
new packet = 00 88 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 00 37 03 80 45 14 00 14 00 15 00 17 00 58 FB A8
Segmentation fault: 11

Note that the fourth from the last byte should be D9.

Work around seems to be to use a large VecDeqeue capacity.

Here's the code:

use std::collections::VecDeque;
use std::fmt;

pub struct Packet
{
	pub payload: VecDeque<u8>,
}

pub struct Header
{
	pub data: Vec<u8>,
}

impl Packet
{
	pub fn new() -> Self
	{
		let payload = VecDeque::with_capacity(32);
		Packet{payload}
	}

	pub fn len(&self) -> usize
	{
		self.payload.len()
	}

	pub fn push_header(&mut self, header: &Header)
	{
		self.payload.reserve(header.data.len());
		for b in header.data.iter().rev() {
			self.payload.push_front(*b);
		}
	}

	pub fn push_back_bytes(&mut self, data: &[u8])
	{
		self.payload.extend(data.iter());
	}
}

impl fmt::Debug for Packet 
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		let mut bytes = String::with_capacity(3*self.len());
		for i in 0..self.payload.len() {
			bytes.push_str(&format!(" {:02X}", self.payload[i]));
		}

        write!(f, "{}", bytes)
    }
}

impl Header
{
	pub fn new() -> Self
	{
		let data = Vec::with_capacity(20);
		Header{data}
	}

	pub fn with_capacity(capacity: usize) -> Self
	{
		let data = Vec::with_capacity(capacity);
		Header{data}
	}

	pub fn push8(&mut self, data: u8)
	{
		self.data.push(data);
	}

	pub fn push16(&mut self, data: u16)
	{
		self.data.push((data >> 8) as u8);
		self.data.push((data & 0xFF) as u8);
	}

	pub fn push32(&mut self, data: u32)
	{
		self.data.push((data >> 24) as u8);
		self.data.push(((data >> 16) & 0xFF) as u8);
		self.data.push(((data >> 8) & 0xFF) as u8);
		self.data.push((data & 0xFF) as u8);
	}

	pub fn push_bytes(&mut self, data: &[u8])
	{
		self.data.extend(data);
	}
}

fn push_ipv4(packet: &mut Packet)
{
	let payload_len = packet.len();
	let mut header = Header::with_capacity(20);

	let b = 0x45;						// version + IHL (we don't support options so length is fixed)
	header.push8(b);

	header.push8(20);

	let hw = 20 + payload_len;			// total length
	header.push16(hw as u16);

	header.push16(21);	// identification
	header.push16(23);

	packet.push_header(&header);
}

fn push_mac(packet: &mut Packet)
{
	let mut header = Header::with_capacity(30);

	let hw = 0b1000_10_00;		// frame control, see 9.2.4.1 
	header.push16(hw);

	let addr = [1, 2, 3, 4, 5, 6];
	for &b in addr.iter() {	// address 1, see 9.3.2.1
		header.push8(b);
	}

	for &b in addr.iter() {	// address 2
		header.push8(b);
	}

	for &b in addr.iter() {// address 3
		header.push8(b);
	}

	header.push16(55);

	let hw = 0b111_0_00_0_000;	// QoS control, see 9.2.4.5.1
	header.push16(hw);

	packet.push_header(&header);

	let fcs = [0xD9, 0x58, 0xFB, 0xA8];
	println!("old packet = {:?}", packet);
	println!("pushing {:X} {:X} {:X} {:X} ", fcs[0], fcs[1], fcs[2], fcs[3]);
	packet.push_back_bytes(&fcs);

	println!("new packet = {:?}", packet);
}

fn main()
{
	let mut packet = Packet::new();
	push_ipv4(&mut packet);
	push_mac(&mut packet);
}

Valgrind output with the allocator switched over to alloc_system:

==104800== Memcheck, a memory error detector
==104800== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==104800== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==104800== Command: ./foo
==104800== 
old packet =  00 88 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 00 37 03 80 45 14 00 14 00 15 00 17
pushing D9 58 FB A8 
==104800== Invalid write of size 1
==104800==    at 0x10FE37: core::ptr::write (ptr.rs:330)
==104800==    by 0x10D324: <alloc::vec_deque::VecDeque<T>>::buffer_write (vec_deque.rs:136)
==104800==    by 0x10DB5B: <alloc::vec_deque::VecDeque<T>>::push_back (vec_deque.rs:1124)
==104800==    by 0x1121AF: <alloc::vec_deque::VecDeque<A> as core::iter::traits::Extend<A>>::extend (vec_deque.rs:2424)
==104800==    by 0x10BEB7: <alloc::vec_deque::VecDeque<T> as core::iter::traits::Extend<&'a T>>::extend (vec_deque.rs:2432)
==104800==    by 0x1126F4: foo::Packet::push_back_bytes (foo.rs:44)
==104800==    by 0x113234: foo::push_mac (foo.rs:149)
==104800==    by 0x1132F4: foo::main (foo.rs:158)
==104800==    by 0x1263EC: __rust_maybe_catch_panic (lib.rs:99)
==104800==    by 0x11FE1B: try<(),closure> (panicking.rs:459)
==104800==    by 0x11FE1B: catch_unwind<closure,()> (panic.rs:361)
==104800==    by 0x11FE1B: std::rt::lang_start (rt.rs:59)
==104800==    by 0x113872: main (foo.rs:0)
==104800==  Address 0x5a31d00 is 0 bytes after a block of size 64 alloc'd
==104800==    at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==104800==    by 0x10C211: alloc_system::platform::<impl alloc::allocator::Alloc for &'a alloc_system::System>::alloc (lib.rs:134)
==104800==    by 0x1133DB: __rg_alloc (foo.rs:9)
==104800==    by 0x1118DE: <alloc::heap::Heap as alloc::allocator::Alloc>::alloc (heap.rs:84)
==104800==    by 0x10DEFF: <alloc::raw_vec::RawVec<T, A>>::allocate_in (raw_vec.rs:97)
==104800==    by 0x10D015: <alloc::raw_vec::RawVec<T>>::with_capacity (raw_vec.rs:141)
==104800==    by 0x10D437: <alloc::vec_deque::VecDeque<T>>::with_capacity (vec_deque.rs:400)
==104800==    by 0x112515: foo::Packet::new (foo.rs:25)
==104800==    by 0x1132E0: foo::main (foo.rs:156)
==104800==    by 0x1263EC: __rust_maybe_catch_panic (lib.rs:99)
==104800==    by 0x11FE1B: try<(),closure> (panicking.rs:459)
==104800==    by 0x11FE1B: catch_unwind<closure,()> (panic.rs:361)
==104800==    by 0x11FE1B: std::rt::lang_start (rt.rs:59)
==104800==    by 0x113872: main (foo.rs:0)
==104800== 
==104800== Conditional jump or move depends on uninitialised value(s)
==104800==    at 0x12B3CD: digit (num.rs:143)
==104800==    by 0x12B3CD: fmt_int<core::fmt::num::UpperHex,u8> (num.rs:78)
==104800==    by 0x12B3CD: core::fmt::num::<impl core::fmt::UpperHex for u8>::fmt (num.rs:184)
==104800==    by 0x1298FA: run (mod.rs:1007)
==104800==    by 0x1298FA: core::fmt::write (mod.rs:975)
==104800==    by 0x126B2B: write_fmt<alloc::string::String> (mod.rs:223)
==104800==    by 0x126B2B: alloc::fmt::format (fmt.rs:555)
==104800==    by 0x112947: <foo::Packet as core::fmt::Debug>::fmt (foo.rs:54)
==104800==    by 0x11164F: <&'a mut T as core::fmt::Debug>::fmt (mod.rs:1487)
==104800==    by 0x129950: core::fmt::write (mod.rs:967)
==104800==    by 0x117F8B: write_fmt<std::io::stdio::StdoutLock> (mod.rs:1143)
==104800==    by 0x117F8B: <std::io::stdio::Stdout as std::io::Write>::write_fmt (stdio.rs:461)
==104800==    by 0x11870B: print_to<std::io::stdio::Stdout> (stdio.rs:679)
==104800==    by 0x11870B: std::io::stdio::_print (stdio.rs:701)
==104800==    by 0x1132AA: foo::push_mac (foo.rs:151)
==104800==    by 0x1132F4: foo::main (foo.rs:158)
==104800==    by 0x1263EC: __rust_maybe_catch_panic (lib.rs:99)
==104800==    by 0x11FE1B: try<(),closure> (panicking.rs:459)
==104800==    by 0x11FE1B: catch_unwind<closure,()> (panic.rs:361)
==104800==    by 0x11FE1B: std::rt::lang_start (rt.rs:59)
==104800== 
==104800== Conditional jump or move depends on uninitialised value(s)
==104800==    at 0x12B3DD: fmt_int<core::fmt::num::UpperHex,u8> (num.rs:80)
==104800==    by 0x12B3DD: core::fmt::num::<impl core::fmt::UpperHex for u8>::fmt (num.rs:184)
==104800==    by 0x1298FA: run (mod.rs:1007)
==104800==    by 0x1298FA: core::fmt::write (mod.rs:975)
==104800==    by 0x126B2B: write_fmt<alloc::string::String> (mod.rs:223)
==104800==    by 0x126B2B: alloc::fmt::format (fmt.rs:555)
==104800==    by 0x112947: <foo::Packet as core::fmt::Debug>::fmt (foo.rs:54)
==104800==    by 0x11164F: <&'a mut T as core::fmt::Debug>::fmt (mod.rs:1487)
==104800==    by 0x129950: core::fmt::write (mod.rs:967)
==104800==    by 0x117F8B: write_fmt<std::io::stdio::StdoutLock> (mod.rs:1143)
==104800==    by 0x117F8B: <std::io::stdio::Stdout as std::io::Write>::write_fmt (stdio.rs:461)
==104800==    by 0x11870B: print_to<std::io::stdio::Stdout> (stdio.rs:679)
==104800==    by 0x11870B: std::io::stdio::_print (stdio.rs:701)
==104800==    by 0x1132AA: foo::push_mac (foo.rs:151)
==104800==    by 0x1132F4: foo::main (foo.rs:158)
==104800==    by 0x1263EC: __rust_maybe_catch_panic (lib.rs:99)
==104800==    by 0x11FE1B: try<(),closure> (panicking.rs:459)
==104800==    by 0x11FE1B: catch_unwind<closure,()> (panic.rs:361)
==104800==    by 0x11FE1B: std::rt::lang_start (rt.rs:59)
==104800== 
==104800== Conditional jump or move depends on uninitialised value(s)
==104800==    at 0x4C3149A: memrchr (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==104800==    by 0x118328: memrchr_specific (memchr.rs:39)
==104800==    by 0x118328: memrchr (memchr.rs:56)
==104800==    by 0x118328: memrchr (memchr.rs:55)
==104800==    by 0x118328: write<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:799)
==104800==    by 0x118328: <std::io::stdio::StdoutLock<'a> as std::io::Write>::write (stdio.rs:467)
==104800==    by 0x118B02: std::io::Write::write_all (mod.rs:1072)
==104800==    by 0x119045: <std::io::Write::write_fmt::Adaptor<'a, T> as core::fmt::Write>::write_str (mod.rs:1132)
==104800==    by 0x111601: <alloc::string::String as core::fmt::Display>::fmt (string.rs:1767)
==104800==    by 0x129950: core::fmt::write (mod.rs:967)
==104800==    by 0x12A415: core::fmt::Formatter::write_fmt (mod.rs:1275)
==104800==    by 0x1129EE: <foo::Packet as core::fmt::Debug>::fmt (foo.rs:57)
==104800==    by 0x11164F: <&'a mut T as core::fmt::Debug>::fmt (mod.rs:1487)
==104800==    by 0x129950: core::fmt::write (mod.rs:967)
==104800==    by 0x117F8B: write_fmt<std::io::stdio::StdoutLock> (mod.rs:1143)
==104800==    by 0x117F8B: <std::io::stdio::Stdout as std::io::Write>::write_fmt (stdio.rs:461)
==104800==    by 0x11870B: print_to<std::io::stdio::Stdout> (stdio.rs:679)
==104800==    by 0x11870B: std::io::stdio::_print (stdio.rs:701)
==104800== 
==104800== Syscall param write(buf) points to uninitialised byte(s)
==104800==    at 0x5255884: write (in /usr/lib/libpthread-2.26.so)
==104800==    by 0x1174F0: write (fd.rs:104)
==104800==    by 0x1174F0: write (stdio.rs:35)
==104800==    by 0x1174F0: write (stdio.rs:85)
==104800==    by 0x1174F0: write<std::io::stdio::StdoutRaw> (stdio.rs:101)
==104800==    by 0x1174F0: <std::io::buffered::BufWriter<W>>::flush_buf (buffered.rs:405)
==104800==    by 0x1183BA: flush<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:500)
==104800==    by 0x1183BA: flush<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:828)
==104800==    by 0x1183BA: write<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:812)
==104800==    by 0x1183BA: <std::io::stdio::StdoutLock<'a> as std::io::Write>::write (stdio.rs:467)
==104800==    by 0x118B02: std::io::Write::write_all (mod.rs:1072)
==104800==    by 0x119045: <std::io::Write::write_fmt::Adaptor<'a, T> as core::fmt::Write>::write_str (mod.rs:1132)
==104800==    by 0x129989: core::fmt::write (mod.rs:982)
==104800==    by 0x117F8B: write_fmt<std::io::stdio::StdoutLock> (mod.rs:1143)
==104800==    by 0x117F8B: <std::io::stdio::Stdout as std::io::Write>::write_fmt (stdio.rs:461)
==104800==    by 0x11870B: print_to<std::io::stdio::Stdout> (stdio.rs:679)
==104800==    by 0x11870B: std::io::stdio::_print (stdio.rs:701)
==104800==    by 0x1132AA: foo::push_mac (foo.rs:151)
==104800==    by 0x1132F4: foo::main (foo.rs:158)
==104800==    by 0x1263EC: __rust_maybe_catch_panic (lib.rs:99)
==104800==    by 0x11FE1B: try<(),closure> (panicking.rs:459)
==104800==    by 0x11FE1B: catch_unwind<closure,()> (panic.rs:361)
==104800==    by 0x11FE1B: std::rt::lang_start (rt.rs:59)
==104800==  Address 0x5a31fff is 111 bytes inside a block of size 1,024 alloc'd
==104800==    at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==104800==    by 0x10C211: alloc_system::platform::<impl alloc::allocator::Alloc for &'a alloc_system::System>::alloc (lib.rs:134)
==104800==    by 0x1133DB: __rg_alloc (foo.rs:9)
==104800==    by 0x117C9F: alloc (heap.rs:84)
==104800==    by 0x117C9F: allocate_in<u8,alloc::heap::Heap> (raw_vec.rs:97)
==104800==    by 0x117C9F: with_capacity<u8> (raw_vec.rs:141)
==104800==    by 0x117C9F: with_capacity<u8> (vec.rs:359)
==104800==    by 0x117C9F: with_capacity<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:394)
==104800==    by 0x117C9F: with_capacity<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:712)
==104800==    by 0x117C9F: new<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>> (buffered.rs:691)
==104800==    by 0x117C9F: std::io::stdio::stdout::stdout_init (stdio.rs:411)
==104800==    by 0x117BD2: init<std::sys_common::remutex::ReentrantMutex<core::cell::RefCell<std::io::buffered::LineWriter<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>>>>> (lazy.rs:62)
==104800==    by 0x117BD2: get<std::sys_common::remutex::ReentrantMutex<core::cell::RefCell<std::io::buffered::LineWriter<std::io::stdio::Maybe<std::io::stdio::StdoutRaw>>>>> (lazy.rs:39)
==104800==    by 0x117BD2: std::io::stdio::stdout (stdio.rs:403)
==104800==    by 0x1186D5: print_to<std::io::stdio::Stdout> (stdio.rs:679)
==104800==    by 0x1186D5: std::io::stdio::_print (stdio.rs:701)
==104800==    by 0x113028: foo::push_mac (foo.rs:147)
==104800==    by 0x1132F4: foo::main (foo.rs:158)
==104800==    by 0x1263EC: __rust_maybe_catch_panic (lib.rs:99)
==104800==    by 0x11FE1B: try<(),closure> (panicking.rs:459)
==104800==    by 0x11FE1B: catch_unwind<closure,()> (panic.rs:361)
==104800==    by 0x11FE1B: std::rt::lang_start (rt.rs:59)
==104800==    by 0x113872: main (foo.rs:0)
==104800== 
new packet =  00 88 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 00 37 03 80 45 14 00 14 00 15 00 17 00 58 FB A8
==104800== 
==104800== HEAP SUMMARY:
==104800==     in use at exit: 0 bytes in 0 blocks
==104800==   total heap usage: 163 allocs, 163 frees, 4,228 bytes allocated
==104800== 
==104800== All heap blocks were freed -- no leaks are possible
==104800== 
==104800== For counts of detected and suppressed errors, rerun with: -v
==104800== Use --track-origins=yes to see where uninitialised values come from
==104800== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)

Here is what I believe is a minimal reproduction:

#![feature(global_allocator, alloc_system, allocator_api)]                                                                                                                                                                                             
extern crate alloc_system;                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                       
use std::collections::VecDeque;                                                                                                                                                                                                                        
use alloc_system::System;                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                       
#[global_allocator]                                                                                                                                                                                                                                    
static ALLOCATOR: System = System;                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                       
fn main() {                                                                                                                                                                                                                                            
    let mut deque = VecDeque::with_capacity(32);                                                                                                                                                                                                       
    deque.push_front(0);                                                                                                                                                                                                                               
    deque.reserve(31);                                                                                                                                                                                                                                 
    deque.push_back(0);                                                                                                                                                                                                                                
}

Valgrind:

==107642== Memcheck, a memory error detector                                                                                                                                                                                                           
==107642== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.                                                                                                                                                                             
==107642== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info                                                                                                                                                                          
==107642== Command: ./foo                                                                                                                                                                                                                              
==107642==                                                                                                                                                                                                                                             
==107642== Invalid write of size 4                                                                                                                                                                                                                     
==107642==    at 0x10E364: core::ptr::write (ptr.rs:330)                                                                                                                                                                                               
==107642==    by 0x10C601: <alloc::vec_deque::VecDeque<T>>::buffer_write (vec_deque.rs:136)                                                                                                                                                            
==107642==    by 0x10CD97: <alloc::vec_deque::VecDeque<T>>::push_back (vec_deque.rs:1124)                                                                                                                                                              
==107642==    by 0x10FBEB: foo::main (foo.rs:14)                                                                                                                                                                                                       
==107642==    by 0x120F9C: __rust_maybe_catch_panic (lib.rs:99)                                                                                                                                                                                        
==107642==    by 0x11A9CB: try<(),closure> (panicking.rs:459)                                                                                                                                                                                          
==107642==    by 0x11A9CB: catch_unwind<closure,()> (panic.rs:361)                                                                                                                                                                                     
==107642==    by 0x11A9CB: std::rt::lang_start (rt.rs:59)                                                                                                                                                                                              
==107642==    by 0x110152: main (foo.rs:0)                                                                                                                                                                                                             
==107642==  Address 0x5a31dc0 is 0 bytes after a block of size 256 alloc'd                                                                                                                                                                             
==107642==    at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)                                                                                                                                                            
==107642==    by 0x10BA51: alloc_system::platform::<impl alloc::allocator::Alloc for &'a alloc_system::System>::alloc (lib.rs:134)                                                                                                                     
==107642==    by 0x10FCBB: __rg_alloc (foo.rs:8)                                                                                                                                                                                                       
==107642==    by 0x10F3FE: <alloc::heap::Heap as alloc::allocator::Alloc>::alloc (heap.rs:84)                                                                                                                                                          
==107642==    by 0x10D13F: <alloc::raw_vec::RawVec<T, A>>::allocate_in (raw_vec.rs:97)                                                                                                                                                                 
==107642==    by 0x10C325: <alloc::raw_vec::RawVec<T>>::with_capacity (raw_vec.rs:141)                                                                                                                                                                 
==107642==    by 0x10C717: <alloc::vec_deque::VecDeque<T>>::with_capacity (vec_deque.rs:400)                                                                                                                                                           
==107642==    by 0x10FBA7: foo::main (foo.rs:11)                                                                                                                                                                                                       
==107642==    by 0x120F9C: __rust_maybe_catch_panic (lib.rs:99)                                                                                                                                                                                        
==107642==    by 0x11A9CB: try<(),closure> (panicking.rs:459)                                                                                                                                                                                          
==107642==    by 0x11A9CB: catch_unwind<closure,()> (panic.rs:361)                                                                                                                                                                                     
==107642==    by 0x11A9CB: std::rt::lang_start (rt.rs:59)                                                                                                                                                                                              
==107642==    by 0x110152: main (foo.rs:0)                                                                                                                                                                                                             
==107642==                                                                                                                                                                                                                                             
==107642==                                                                                                                                                                                                                                             
==107642== HEAP SUMMARY:                                                                                                                                                                                                                               
==107642==     in use at exit: 0 bytes in 0 blocks                                                                                                                                                                                                     
==107642==   total heap usage: 15 allocs, 15 frees, 2,478 bytes allocated                                                                                                                                                                              
==107642==                                                                                                                                                                                                                                             
==107642== All heap blocks were freed -- no leaks are possible                                                                                                                                                                                         
==107642==                                                                                                                                                                                                                                             
==107642== For counts of detected and suppressed errors, rerun with: -v                                                                                                                                                                                
==107642== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

It looks like this was introduced two years ago in bfa0e1f. Specifically, VecDeque::reserve mixes up its "raw" capacity and the user-visible capacity. These differ by one, so reserve can end up in a situation where it calls into handle_cap_increase without the capacity having actually increased. The implementation of that method assumes this doesn't happen, and as a result messes up the head and tail pointers so that the next push writes off the end of the buffer.

Making a fix right now.

This bug is referenced in CVE-2018-1000657:

Rust Programming Language Rust standard library version Commit bfa0e1f and later; stable release 1.3.0 and later contains a Buffer Overflow vulnerability in std::collections::vec_deque::VecDeque::reserve() function that can result in Arbitrary code execution, but no proof-of-concept exploit is currently published.. This vulnerability appears to have been fixed in after commit fdfafb5; stable release 1.22.0 and later.