Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions rust/flexbuffers/src/reader/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,11 @@ impl<B: Buffer> MapReader<B> {
// Using &CStr will eagerly compute the length of the key. &str needs length info AND utf8
// validation. This version is faster than both.
fn lazy_strcmp(&self, key_addr: usize, key: &str) -> Ordering {
// TODO: Can we know this won't OOB and panic?
let k = self.buffer[key_addr..].iter().take_while(|&&b| b != b'\0');
let tail = match self.buffer.get(key_addr..) {
Some(s) => s,
None => return Ordering::Less,
};
let k = tail.iter().take_while(|&&b| b != b'\0');
k.cmp(key.as_bytes().iter())
}

Expand All @@ -89,7 +92,9 @@ impl<B: Buffer> MapReader<B> {
let (mut low, mut high) = (0, self.length);
while low < high {
let i = (low + high) / 2;
let key_offset_address = self.keys_address + i * self.keys_width.n_bytes();
let key_offset_address = i
.checked_mul(self.keys_width.n_bytes())
.and_then(|offset| self.keys_address.checked_add(offset))?;
let key_address =
deref_offset(&self.buffer, key_offset_address, self.keys_width).ok()?;
match self.lazy_strcmp(key_address, key) {
Expand All @@ -115,8 +120,19 @@ impl<B: Buffer> MapReader<B> {
if i >= self.length {
return Err(Error::IndexOutOfBounds);
}
let data_address = self.values_address + self.values_width.n_bytes() * i;
let type_address = self.values_address + self.values_width.n_bytes() * self.length + i;
let data_address = self
.values_width
.n_bytes()
.checked_mul(i)
.and_then(|offset| self.values_address.checked_add(offset))
.ok_or(Error::FlexbufferOutOfBounds)?;
let type_address = self
.values_width
.n_bytes()
.checked_mul(self.length)
.and_then(|offset| self.values_address.checked_add(offset))
.and_then(|addr| addr.checked_add(i))
.ok_or(Error::FlexbufferOutOfBounds)?;
let (fxb_type, width) = self
.buffer
.get(type_address)
Expand Down
48 changes: 40 additions & 8 deletions rust/flexbuffers/src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,14 @@ impl<B: Buffer> Reader<B> {
if self.bitwidth().n_bytes() != std::mem::size_of::<T>() {
self.expect_bw(T::WIDTH)?;
}
let end = self.address + self.length() * std::mem::size_of::<T>();
let byte_len = self
.length()
.checked_mul(std::mem::size_of::<T>())
.ok_or(Error::FlexbufferOutOfBounds)?;
let end = self
.address
.checked_add(byte_len)
.ok_or(Error::FlexbufferOutOfBounds)?;
let slice: &[u8] =
self.buffer.get(self.address..end).ok_or(Error::FlexbufferOutOfBounds)?;

Expand All @@ -323,7 +330,12 @@ impl<B: Buffer> Reader<B> {
/// Otherwise Returns error.
pub fn get_bool(&self) -> Result<bool, Error> {
self.expect_type(FlexBufferType::Bool)?;
Ok(self.buffer[self.address..self.address + self.width.n_bytes()].iter().any(|&b| b != 0))
let end = self.address + self.width.n_bytes();
let slice = self
.buffer
.get(self.address..end)
.ok_or(Error::FlexbufferOutOfBounds)?;
Ok(slice.iter().any(|&b| b != 0))
}

/// Gets the length of the key if this type is a key.
Expand All @@ -332,7 +344,11 @@ impl<B: Buffer> Reader<B> {
#[inline]
fn get_key_len(&self) -> Result<usize, Error> {
self.expect_type(FlexBufferType::Key)?;
let (length, _) = self.buffer[self.address..]
let tail = self
.buffer
.get(self.address..)
.ok_or(Error::FlexbufferOutOfBounds)?;
let (length, _) = tail
.iter()
.enumerate()
.find(|(_, &b)| b == b'\0')
Expand All @@ -342,18 +358,27 @@ impl<B: Buffer> Reader<B> {

/// Retrieves the string value up until the first `\0` character.
pub fn get_key(&self) -> Result<B::BufferString, Error> {
let key_len = self.get_key_len()?;
let end = self
.address
.checked_add(key_len)
.ok_or(Error::FlexbufferOutOfBounds)?;
let bytes = self
.buffer
.slice(self.address..self.address + self.get_key_len()?)
.slice(self.address..end)
.ok_or(Error::IndexOutOfBounds)?;
Ok(bytes.buffer_str()?)
}

pub fn get_blob(&self) -> Result<Blob<B>, Error> {
self.expect_type(FlexBufferType::Blob)?;
let end = self
.address
.checked_add(self.length())
.ok_or(Error::FlexbufferOutOfBounds)?;
Ok(Blob(
self.buffer
.slice(self.address..self.address + self.length())
.slice(self.address..end)
.ok_or(Error::IndexOutOfBounds)?,
))
}
Expand All @@ -366,7 +391,11 @@ impl<B: Buffer> Reader<B> {
/// is out of bounds.
pub fn get_str(&self) -> Result<B::BufferString, Error> {
self.expect_type(FlexBufferType::String)?;
let bytes = self.buffer.slice(self.address..self.address + self.length());
let end = self
.address
.checked_add(self.length())
.ok_or(Error::FlexbufferOutOfBounds)?;
let bytes = self.buffer.slice(self.address..end);
Ok(bytes.ok_or(Error::ReadUsizeOverflowed)?.buffer_str()?)
}

Expand Down Expand Up @@ -601,9 +630,12 @@ fn f64_from_le_bytes(bytes: [u8; 8]) -> f64 {
}

fn read_usize(buffer: &[u8], address: usize, width: BitWidth) -> usize {
let cursor = &buffer[address..];
let cursor = match buffer.get(address..) {
Some(c) => c,
None => return 0,
};
match width {
BitWidth::W8 => cursor[0] as usize,
BitWidth::W8 => cursor.first().copied().unwrap_or_default() as usize,
BitWidth::W16 => cursor
.get(0..2)
.and_then(|s| s.try_into().ok())
Expand Down
16 changes: 13 additions & 3 deletions rust/flexbuffers/src/reader/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@ impl<B: Buffer> VectorReader<B> {
if let Some(ty) = self.reader.fxb_type.typed_vector_type() {
Ok((ty, self.reader.width))
} else {
let types_addr = self.reader.address + self.length * self.reader.width.n_bytes();
let types_addr = self
.length
.checked_mul(self.reader.width.n_bytes())
.and_then(|offset| self.reader.address.checked_add(offset))
.ok_or(Error::FlexbufferOutOfBounds)?;
self.reader
.buffer
.get(types_addr + i)
.get(types_addr.checked_add(i).ok_or(Error::FlexbufferOutOfBounds)?)
.ok_or(Error::FlexbufferOutOfBounds)
.and_then(|&t| unpack_type(t))
}
Expand All @@ -70,7 +74,13 @@ impl<B: Buffer> VectorReader<B> {
return Err(Error::IndexOutOfBounds);
}
let (fxb_type, bw) = self.get_elem_type(i)?;
let data_address = self.reader.address + self.reader.width.n_bytes() * i;
let data_address = self
.reader
.width
.n_bytes()
.checked_mul(i)
.and_then(|offset| self.reader.address.checked_add(offset))
.ok_or(Error::FlexbufferOutOfBounds)?;
Reader::new(
self.reader.buffer.shallow_copy(),
data_address,
Expand Down