Description
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);
}