Fix Rust UB problems (#6393)

* Fix miri problems by assuming alignment is 1 in rust

* Removed is_aligned fn from rust verifier.

* Add back is_aligned, but make it w.r.t. buffer[0]

* touch unused variable

* touch unused variable

* +nightly

* Move Rust miri testing into its own docker

* fix bash

* missing one endian conversion

* fix endianness2

* format stuff

Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
Casper
2021-01-11 15:24:52 -05:00
committed by GitHub
parent 39e115fdb4
commit 408cf58024
17 changed files with 540 additions and 197 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "flatbuffers"
version = "0.8.0"
version = "0.8.1"
edition = "2018"
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
license = "Apache-2.0"

View File

@@ -150,11 +150,13 @@ pub fn byte_swap_f64(x: f64) -> f64 {
/// endian conversion, if necessary.
#[inline]
pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
let sz = size_of::<T>();
let mut_ptr = (&mut s[..sz]).as_mut_ptr() as *mut T;
let val = x.to_little_endian();
let x_le = x.to_little_endian();
unsafe {
*mut_ptr = val;
core::ptr::copy_nonoverlapping(
&x_le as *const T as *const u8,
s.as_mut_ptr() as *mut u8,
size_of::<T>()
);
}
}
@@ -162,18 +164,22 @@ pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
/// Performs endian conversion, if necessary.
#[inline]
pub fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T {
let buf = &s[loc..loc + size_of::<T>()];
read_scalar(buf)
read_scalar(&s[loc..])
}
/// Read an EndianScalar from the provided byte slice. Performs endian
/// conversion, if necessary.
#[inline]
pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
let sz = size_of::<T>();
let p = (&s[..sz]).as_ptr() as *const T;
let x = unsafe { *p };
let mut mem = core::mem::MaybeUninit::<T>::uninit();
// Since [u8] has alignment 1, we copy it into T which may have higher alignment.
let x = unsafe {
core::ptr::copy_nonoverlapping(
s.as_ptr(),
mem.as_mut_ptr() as *mut u8,
size_of::<T>()
);
mem.assume_init()
};
x.from_little_endian()
}

View File

@@ -232,12 +232,16 @@ impl<'opts, 'buf> Verifier<'opts, 'buf> {
self.num_tables = 0;
self.num_tables = 0;
}
/// Check that there really is a T in there.
/// Checks `pos` is aligned to T's alignment. This does not mean `buffer[pos]` is aligned w.r.t
/// memory since `buffer: &[u8]` has alignment 1.
///
/// ### WARNING
/// This does not work for flatbuffers-structs as they have alignment 1 according to
/// `core::mem::align_of` but are meant to have higher alignment within a Flatbuffer w.r.t.
/// `buffer[0]`. TODO(caspern).
#[inline]
fn is_aligned<T>(&self, pos: usize) -> Result<()> {
// Safe because we're not dereferencing.
let p = unsafe { self.buffer.as_ptr().add(pos) };
if (p as usize) % std::mem::align_of::<T>() == 0 {
if pos % std::mem::align_of::<T>() == 0 {
Ok(())
} else {
Err(InvalidFlatbuffer::Unaligned {
@@ -259,6 +263,7 @@ impl<'opts, 'buf> Verifier<'opts, 'buf> {
}
Ok(())
}
/// Check that there really is a T in there.
#[inline]
pub fn in_buffer<T>(&mut self, pos: usize) -> Result<()> {
self.is_aligned::<T>(pos)?;