// Copyright 2019 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use std::cmp; use std::collections::VecDeque; use std::fmt::{self, Display}; use std::io::{self, Read, Write}; use std::mem::{size_of, MaybeUninit}; use std::result; use data_model::{DataInit, Le16, Le32, Le64, VolatileMemory, VolatileMemoryError, VolatileSlice}; use sys_util::{FileReadWriteAtVolatile, FileReadWriteVolatile, GuestAddress, GuestMemory}; use super::DescriptorChain; #[derive(Debug)] pub enum Error { DescriptorChainOverflow, GuestMemoryError(sys_util::GuestMemoryError), InvalidChain, IoError(io::Error), SplitOutOfBounds(usize), VolatileMemoryError(VolatileMemoryError), } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; match self { DescriptorChainOverflow => write!( f, "the combined length of all the buffers in a `DescriptorChain` would overflow" ), GuestMemoryError(e) => write!(f, "descriptor guest memory error: {}", e), InvalidChain => write!(f, "invalid descriptor chain"), IoError(e) => write!(f, "descriptor I/O error: {}", e), SplitOutOfBounds(off) => write!(f, "`DescriptorChain` split is out of bounds: {}", off), VolatileMemoryError(e) => write!(f, "volatile memory error: {}", e), } } } pub type Result = result::Result; impl std::error::Error for Error {} #[derive(Clone)] struct DescriptorChainConsumer<'a> { buffers: VecDeque>, bytes_consumed: usize, } impl<'a> DescriptorChainConsumer<'a> { fn available_bytes(&self) -> Result { self.buffers .iter() .try_fold(0usize, |count, vs| count.checked_add(vs.size() as usize)) .ok_or(Error::DescriptorChainOverflow) } fn bytes_consumed(&self) -> usize { self.bytes_consumed } /// Consumes at most `count` bytes from the `DescriptorChain`. Callers must provide a function /// that takes a `&[VolatileSlice]` and returns the total number of bytes consumed. This /// function guarantees that the combined length of all the slices in the `&[VolatileSlice]` is /// less than or equal to `count`. /// /// # Errors /// /// If the provided function returns any error then no bytes are consumed from the buffer and /// the error is returned to the caller. fn consume(&mut self, count: usize, f: F) -> io::Result where F: FnOnce(&[VolatileSlice]) -> io::Result, { let mut buflen = 0; let mut bufs = Vec::with_capacity(self.buffers.len()); for &vs in &self.buffers { if buflen >= count { break; } let rem = count - buflen; if (rem as u64) < vs.size() { let buf = vs.sub_slice(0, rem as u64).map_err(|e| { io::Error::new(io::ErrorKind::InvalidData, Error::VolatileMemoryError(e)) })?; bufs.push(buf); buflen += rem; } else { bufs.push(vs); buflen += vs.size() as usize; } } if bufs.is_empty() { return Ok(0); } let bytes_consumed = f(&*bufs)?; // This can happen if a driver tricks a device into reading/writing more data than // fits in a `usize`. let total_bytes_consumed = self.bytes_consumed .checked_add(bytes_consumed) .ok_or_else(|| { io::Error::new(io::ErrorKind::InvalidData, Error::DescriptorChainOverflow) })?; let mut rem = bytes_consumed; while let Some(vs) = self.buffers.pop_front() { if (rem as u64) < vs.size() { // Split the slice and push the remainder back into the buffer list. Safe because we // know that `rem` is not out of bounds due to the check and we checked the bounds // on `vs` when we added it to the buffer list. self.buffers.push_front(vs.offset(rem as u64).unwrap()); break; } // No need for checked math because we know that `vs.size() <= rem`. rem -= vs.size() as usize; } self.bytes_consumed = total_bytes_consumed; Ok(bytes_consumed) } fn split_at(&mut self, offset: usize) -> Result> { let mut rem = offset; let pos = self.buffers.iter().position(|vs| { if (rem as u64) < vs.size() { true } else { rem -= vs.size() as usize; false } }); if let Some(at) = pos { let mut other = self.buffers.split_off(at); if rem > 0 { // There must be at least one element in `other` because we checked // its `size` value in the call to `position` above. let front = other.pop_front().expect("empty VecDeque after split"); self.buffers.push_back( front .sub_slice(0, rem as u64) .map_err(Error::VolatileMemoryError)?, ); other.push_front( front .offset(rem as u64) .map_err(Error::VolatileMemoryError)?, ); } Ok(DescriptorChainConsumer { buffers: other, bytes_consumed: 0, }) } else if rem == 0 { Ok(DescriptorChainConsumer { buffers: VecDeque::new(), bytes_consumed: 0, }) } else { Err(Error::SplitOutOfBounds(offset)) } } } /// Provides high-level interface over the sequence of memory regions /// defined by readable descriptors in the descriptor chain. /// /// Note that virtio spec requires driver to place any device-writable /// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1). /// Reader will skip iterating over descriptor chain when first writable /// descriptor is encountered. #[derive(Clone)] pub struct Reader<'a> { buffer: DescriptorChainConsumer<'a>, } impl<'a> Reader<'a> { /// Construct a new Reader wrapper over `desc_chain`. pub fn new(mem: &'a GuestMemory, desc_chain: DescriptorChain<'a>) -> Result> { // TODO(jstaron): Update this code to take the indirect descriptors into account. let buffers = desc_chain .into_iter() .readable() .map(|desc| { mem.get_slice(desc.addr.offset(), desc.len.into()) .map_err(Error::VolatileMemoryError) }) .collect::>>>()?; Ok(Reader { buffer: DescriptorChainConsumer { buffers, bytes_consumed: 0, }, }) } /// Reads an object from the descriptor chain buffer. pub fn read_obj(&mut self) -> io::Result { let mut obj = MaybeUninit::::uninit(); // Safe because `MaybeUninit` guarantees that the pointer is valid for // `size_of::()` bytes. let buf = unsafe { ::std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::()) }; self.read_exact(buf)?; // Safe because any type that implements `DataInit` can be considered initialized // even if it is filled with random data. Ok(unsafe { obj.assume_init() }) } /// Reads data from the descriptor chain buffer into a file descriptor. /// Returns the number of bytes read from the descriptor chain buffer. /// The number of bytes read can be less than `count` if there isn't /// enough data in the descriptor chain buffer. pub fn read_to( &mut self, mut dst: F, count: usize, ) -> io::Result { self.buffer .consume(count, |bufs| dst.write_vectored_volatile(bufs)) } /// Reads data from the descriptor chain buffer into a File at offset `off`. /// Returns the number of bytes read from the descriptor chain buffer. /// The number of bytes read can be less than `count` if there isn't /// enough data in the descriptor chain buffer. pub fn read_to_at( &mut self, mut dst: F, count: usize, off: u64, ) -> io::Result { self.buffer .consume(count, |bufs| dst.write_vectored_at_volatile(bufs, off)) } pub fn read_exact_to( &mut self, mut dst: F, mut count: usize, ) -> io::Result<()> { while count > 0 { match self.read_to(&mut dst, count) { Ok(0) => { return Err(io::Error::new( io::ErrorKind::UnexpectedEof, "failed to fill whole buffer", )) } Ok(n) => count -= n, Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) => return Err(e), } } Ok(()) } /// Returns number of bytes available for reading. May return an error if the combined /// lengths of all the buffers in the DescriptorChain would cause an integer overflow. pub fn available_bytes(&self) -> Result { self.buffer.available_bytes() } /// Returns number of bytes already read from the descriptor chain buffer. pub fn bytes_read(&self) -> usize { self.buffer.bytes_consumed() } /// Splits this `Reader` into two at the given offset in the `DescriptorChain` buffer. /// After the split, `self` will be able to read up to `offset` bytes while the returned /// `Reader` can read up to `available_bytes() - offset` bytes. Returns an error if /// `offset > self.available_bytes()`. pub fn split_at(&mut self, offset: usize) -> Result> { self.buffer.split_at(offset).map(|buffer| Reader { buffer }) } } impl<'a> io::Read for Reader<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.buffer.consume(buf.len(), |bufs| { if let Some(vs) = bufs.first() { // This is guaranteed by the implementation of `consume`. debug_assert_eq!(vs.size(), cmp::min(buf.len() as u64, vs.size())); vs.copy_to(buf); Ok(vs.size() as usize) } else { Ok(0) } }) } } /// Provides high-level interface over the sequence of memory regions /// defined by writable descriptors in the descriptor chain. /// /// Note that virtio spec requires driver to place any device-writable /// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1). /// Writer will start iterating the descriptors from the first writable one and will /// assume that all following descriptors are writable. #[derive(Clone)] pub struct Writer<'a> { buffer: DescriptorChainConsumer<'a>, } impl<'a> Writer<'a> { /// Construct a new Writer wrapper over `desc_chain`. pub fn new(mem: &'a GuestMemory, desc_chain: DescriptorChain<'a>) -> Result> { let buffers = desc_chain .into_iter() .writable() .map(|desc| { mem.get_slice(desc.addr.offset(), desc.len.into()) .map_err(Error::VolatileMemoryError) }) .collect::>>>()?; Ok(Writer { buffer: DescriptorChainConsumer { buffers, bytes_consumed: 0, }, }) } /// Writes an object to the descriptor chain buffer. pub fn write_obj(&mut self, val: T) -> io::Result<()> { self.write_all(val.as_slice()) } /// Returns number of bytes available for writing. May return an error if the combined /// lengths of all the buffers in the DescriptorChain would cause an overflow. pub fn available_bytes(&self) -> Result { self.buffer.available_bytes() } /// Writes data to the descriptor chain buffer from a file descriptor. /// Returns the number of bytes written to the descriptor chain buffer. /// The number of bytes written can be less than `count` if /// there isn't enough data in the descriptor chain buffer. pub fn write_from( &mut self, mut src: F, count: usize, ) -> io::Result { self.buffer .consume(count, |bufs| src.read_vectored_volatile(bufs)) } /// Writes data to the descriptor chain buffer from a File at offset `off`. /// Returns the number of bytes written to the descriptor chain buffer. /// The number of bytes written can be less than `count` if /// there isn't enough data in the descriptor chain buffer. pub fn write_from_at( &mut self, mut src: F, count: usize, off: u64, ) -> io::Result { self.buffer .consume(count, |bufs| src.read_vectored_at_volatile(bufs, off)) } pub fn write_all_from( &mut self, mut src: F, mut count: usize, ) -> io::Result<()> { while count > 0 { match self.write_from(&mut src, count) { Ok(0) => { return Err(io::Error::new( io::ErrorKind::WriteZero, "failed to write whole buffer", )) } Ok(n) => count -= n, Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) => return Err(e), } } Ok(()) } /// Returns number of bytes already written to the descriptor chain buffer. pub fn bytes_written(&self) -> usize { self.buffer.bytes_consumed() } /// Splits this `Writer` into two at the given offset in the `DescriptorChain` buffer. /// After the split, `self` will be able to write up to `offset` bytes while the returned /// `Writer` can write up to `available_bytes() - offset` bytes. Returns an error if /// `offset > self.available_bytes()`. pub fn split_at(&mut self, offset: usize) -> Result> { self.buffer.split_at(offset).map(|buffer| Writer { buffer }) } } impl<'a> io::Write for Writer<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.buffer.consume(buf.len(), |bufs| { if let Some(vs) = bufs.first() { // This is guaranteed by the implementation of `consume`. debug_assert_eq!(vs.size(), cmp::min(buf.len() as u64, vs.size())); vs.copy_from(buf); Ok(vs.size() as usize) } else { Ok(0) } }) } fn flush(&mut self) -> io::Result<()> { // Nothing to flush since the writes go straight into the buffer. Ok(()) } } const VIRTQ_DESC_F_NEXT: u16 = 0x1; const VIRTQ_DESC_F_WRITE: u16 = 0x2; #[derive(Copy, Clone, PartialEq, Eq)] pub enum DescriptorType { Readable, Writable, } #[derive(Copy, Clone, Debug)] #[repr(C)] struct virtq_desc { addr: Le64, len: Le32, flags: Le16, next: Le16, } // Safe because it only has data and has no implicit padding. unsafe impl DataInit for virtq_desc {} /// Test utility function to create a descriptor chain in guest memory. pub fn create_descriptor_chain( memory: &GuestMemory, descriptor_array_addr: GuestAddress, mut buffers_start_addr: GuestAddress, descriptors: Vec<(DescriptorType, u32)>, spaces_between_regions: u32, ) -> Result { let descriptors_len = descriptors.len(); for (index, (type_, size)) in descriptors.into_iter().enumerate() { let mut flags = 0; if let DescriptorType::Writable = type_ { flags |= VIRTQ_DESC_F_WRITE; } if index + 1 < descriptors_len { flags |= VIRTQ_DESC_F_NEXT; } let index = index as u16; let desc = virtq_desc { addr: buffers_start_addr.offset().into(), len: size.into(), flags: flags.into(), next: (index + 1).into(), }; let offset = size + spaces_between_regions; buffers_start_addr = buffers_start_addr .checked_add(offset as u64) .ok_or(Error::InvalidChain)?; let _ = memory.write_obj_at_addr( desc, descriptor_array_addr .checked_add(index as u64 * std::mem::size_of::() as u64) .ok_or(Error::InvalidChain)?, ); } DescriptorChain::checked_new(memory, descriptor_array_addr, 0x100, 0, 0) .ok_or(Error::InvalidChain) } #[cfg(test)] mod tests { use super::*; use sys_util::{MemfdSeals, SharedMemory}; #[test] fn reader_test_simple_chain() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 8), (Readable, 16), (Readable, 18), (Readable, 64), ], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 106 ); assert_eq!(reader.bytes_read(), 0); let mut buffer = [0 as u8; 64]; if let Err(_) = reader.read_exact(&mut buffer) { panic!("read_exact should not fail here"); } assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 42 ); assert_eq!(reader.bytes_read(), 64); match reader.read(&mut buffer) { Err(_) => panic!("read should not fail here"), Ok(length) => assert_eq!(length, 42), } assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(reader.bytes_read(), 106); } #[test] fn writer_test_simple_chain() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Writable, 8), (Writable, 16), (Writable, 18), (Writable, 64), ], 0, ) .expect("create_descriptor_chain failed");; let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 106 ); assert_eq!(writer.bytes_written(), 0); let mut buffer = [0 as u8; 64]; if let Err(_) = writer.write_all(&mut buffer) { panic!("write_all should not fail here"); } assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 42 ); assert_eq!(writer.bytes_written(), 64); match writer.write(&mut buffer) { Err(_) => panic!("write should not fail here"), Ok(length) => assert_eq!(length, 42), } assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(writer.bytes_written(), 106); } #[test] fn reader_test_incompatible_chain() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Writable, 8)], 0, ) .expect("create_descriptor_chain failed");; let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(reader.bytes_read(), 0); assert!(reader.read_obj::().is_err()); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(reader.bytes_read(), 0); } #[test] fn writer_test_incompatible_chain() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Readable, 8)], 0, ) .expect("create_descriptor_chain failed");; let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(writer.bytes_written(), 0); assert!(writer.write_obj(0u8).is_err()); assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(writer.bytes_written(), 0); } #[test] fn reader_failing_io() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Readable, 256), (Readable, 256)], 0, ) .expect("create_descriptor_chain failed");; let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); // GuestMemory's write_from_memory requires raw file descriptor. let mut shm = SharedMemory::anon().unwrap(); shm.set_size(384).unwrap(); // Prevent shared memory from growing on `write` call. let mut fd_seals = MemfdSeals::new(); fd_seals.set_grow_seal(); shm.add_seals(fd_seals).unwrap(); reader .read_exact_to(&mut shm, 512) .expect_err("successfully read more bytes than SharedMemory size"); // Linux doesn't do partial writes if you give a buffer larger than the remaining length of // the shared memory. And since we passed an iovec with the full contents of the // DescriptorChain we ended up not writing any bytes at all. assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 512 ); assert_eq!(reader.bytes_read(), 0); } #[test] fn writer_failing_io() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Writable, 256), (Writable, 256)], 0, ) .expect("create_descriptor_chain failed"); let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); // GuestMemory's read_to_memory requires raw file descriptor. let mut shm = SharedMemory::anon().unwrap(); shm.set_size(384).unwrap(); writer .write_all_from(&mut shm, 512) .expect_err("successfully wrote more bytes than in SharedMemory"); assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 128 ); assert_eq!(writer.bytes_written(), 384); } #[test] fn reader_writer_shared_chain() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 16), (Readable, 16), (Readable, 96), (Writable, 64), (Writable, 1), (Writable, 3), ], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain.clone()).expect("failed to create Reader"); let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); assert_eq!(reader.bytes_read(), 0); assert_eq!(writer.bytes_written(), 0); let mut buffer = Vec::with_capacity(200); assert_eq!( reader .read_to_end(&mut buffer) .expect("read should not fail here"), 128 ); // The writable descriptors are only 68 bytes long. writer .write_all(&buffer[..68]) .expect("write should not fail here"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(reader.bytes_read(), 128); assert_eq!( writer .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!(writer.bytes_written(), 68); } #[test] fn reader_writer_shattered_object() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let secret: Le32 = 0x12345678.into(); // Create a descriptor chain with memory regions that are properly separated. let chain_writer = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Writable, 1), (Writable, 1), (Writable, 1), (Writable, 1)], 123, ) .expect("create_descriptor_chain failed"); let mut writer = Writer::new(&memory, chain_writer).expect("failed to create Writer"); if let Err(_) = writer.write_obj(secret) { panic!("write_obj should not fail here"); } // Now create new descriptor chain pointing to the same memory and try to read it. let chain_reader = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Readable, 1), (Readable, 1), (Readable, 1), (Readable, 1)], 123, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain_reader).expect("failed to create Reader"); match reader.read_obj::() { Err(_) => panic!("read_obj should not fail here"), Ok(read_secret) => assert_eq!(read_secret, secret), } } #[test] fn reader_unexpected_eof() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![(Readable, 256), (Readable, 256)], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); let mut buf = Vec::with_capacity(1024); buf.resize(1024, 0); assert_eq!( reader .read_exact(&mut buf[..]) .expect_err("read more bytes than available") .kind(), io::ErrorKind::UnexpectedEof ); } #[test] fn split_border() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 16), (Readable, 16), (Readable, 96), (Writable, 64), (Writable, 1), (Writable, 3), ], 0, ) .expect("create_descriptor_chain failed");; let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); let other = reader.split_at(32).expect("failed to split Reader"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 32 ); assert_eq!( other .available_bytes() .expect("failed to get available bytes"), 96 ); } #[test] fn split_middle() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 16), (Readable, 16), (Readable, 96), (Writable, 64), (Writable, 1), (Writable, 3), ], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); let other = reader.split_at(24).expect("failed to split Reader"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 24 ); assert_eq!( other .available_bytes() .expect("failed to get available bytes"), 104 ); } #[test] fn split_end() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 16), (Readable, 16), (Readable, 96), (Writable, 64), (Writable, 1), (Writable, 3), ], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); let other = reader.split_at(128).expect("failed to split Reader"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 128 ); assert_eq!( other .available_bytes() .expect("failed to get available bytes"), 0 ); } #[test] fn split_beginning() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 16), (Readable, 16), (Readable, 96), (Writable, 64), (Writable, 1), (Writable, 3), ], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); let other = reader.split_at(0).expect("failed to split Reader"); assert_eq!( reader .available_bytes() .expect("failed to get available bytes"), 0 ); assert_eq!( other .available_bytes() .expect("failed to get available bytes"), 128 ); } #[test] fn split_outofbounds() { use DescriptorType::*; let memory_start_addr = GuestAddress(0x0); let memory = GuestMemory::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); let chain = create_descriptor_chain( &memory, GuestAddress(0x0), GuestAddress(0x100), vec![ (Readable, 16), (Readable, 16), (Readable, 96), (Writable, 64), (Writable, 1), (Writable, 3), ], 0, ) .expect("create_descriptor_chain failed"); let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); if let Ok(_) = reader.split_at(256) { panic!("successfully split Reader with out of bounds offset"); } } }