Rust Flatbuffers Verifier (#6269)

* Updated comments and fixed a fundemental type error.

* bump rust flatbuffers semver

* Initial commit with verifier, need to clean up

* Verifier tested. Needs clean up and refactoring.

* Display for InvalidFlatbuffer and better errors for strings

* SimpleToVerify, some refactoring

* Combined VerifierType TableAccessorFuncBody into FollowType

* scrub todos

* Update Rust get_root functions.

There are 6 variants, with verifier options, default verifier options
and no verification "fast".

* Rename root fns

* inline

* Update to use thiserror

* fix for bad compiler

* improve error formatting

* Replace multiply with saturating_multiply

* saturating adds too

* Add docs disclaiming experimental verification system

Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
Casper
2020-12-07 18:37:51 -05:00
committed by GitHub
parent 9064072e8c
commit 442949bc11
21 changed files with 1861 additions and 305 deletions

View File

@@ -77,7 +77,8 @@ impl<'a> flatbuffers::Follow<'a> for Color {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self(flatbuffers::read_scalar_at::<i8>(buf, loc))
let b = flatbuffers::read_scalar_at::<i8>(buf, loc);
Self(b)
}
}
@@ -92,14 +93,27 @@ impl flatbuffers::Push for Color {
impl flatbuffers::EndianScalar for Color {
#[inline]
fn to_little_endian(self) -> Self {
Self(i8::to_le(self.0))
let b = i8::to_le(self.0);
Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
Self(i8::from_le(self.0))
let b = i8::from_le(self.0);
Self(b)
}
}
impl<'a> flatbuffers::Verifiable for Color {
#[inline]
fn run_verifier<'o, 'b>(
v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
i8::run_verifier(v, pos)
}
}
impl flatbuffers::SimpleToVerifyInSlice for Color {}
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_EQUIPMENT: u8 = 0;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
@@ -143,11 +157,13 @@ impl std::fmt::Debug for Equipment {
}
}
}
pub struct EquipmentUnionTableOffset {}
impl<'a> flatbuffers::Follow<'a> for Equipment {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self(flatbuffers::read_scalar_at::<u8>(buf, loc))
let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
Self(b)
}
}
@@ -162,15 +178,27 @@ impl flatbuffers::Push for Equipment {
impl flatbuffers::EndianScalar for Equipment {
#[inline]
fn to_little_endian(self) -> Self {
Self(u8::to_le(self.0))
let b = u8::to_le(self.0);
Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
Self(u8::from_le(self.0))
let b = u8::from_le(self.0);
Self(b)
}
}
pub struct EquipmentUnionTableOffset {}
impl<'a> flatbuffers::Verifiable for Equipment {
#[inline]
fn run_verifier<'o, 'b>(
v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
u8::run_verifier(v, pos)
}
}
impl flatbuffers::SimpleToVerifyInSlice for Equipment {}
// struct Vec3, aligned to 4
#[repr(C, align(4))]
#[derive(Clone, Copy, PartialEq)]
@@ -189,6 +217,7 @@ impl std::fmt::Debug for Vec3 {
}
}
impl flatbuffers::SimpleToVerifyInSlice for Vec3 {}
impl flatbuffers::SafeSliceAccess for Vec3 {}
impl<'a> flatbuffers::Follow<'a> for Vec3 {
type Inner = &'a Vec3;
@@ -226,7 +255,15 @@ impl<'b> flatbuffers::Push for &'b Vec3 {
}
}
impl<'a> flatbuffers::Verifiable for Vec3 {
#[inline]
fn run_verifier<'o, 'b>(
v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.in_buffer::<Self>(pos)
}
}
impl Vec3 {
pub fn new(_x: f32, _y: f32, _z: f32) -> Self {
Vec3 {
@@ -324,7 +361,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn weapons(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Weapon<'a>>>> {
self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Weapon<'a>>>>>(Monster::VT_WEAPONS, None)
self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Weapon>>>>(Monster::VT_WEAPONS, None)
}
#[inline]
pub fn equipped_type(&self) -> Equipment {
@@ -336,7 +373,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn path(&self) -> Option<&'a [Vec3]> {
self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Vec3>>>(Monster::VT_PATH, None).map(|v| v.safe_slice() )
self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, Vec3>>>(Monster::VT_PATH, None).map(|v| v.safe_slice())
}
#[inline]
#[allow(non_snake_case)]
@@ -350,6 +387,31 @@ impl<'a> Monster<'a> {
}
impl flatbuffers::Verifiable for Monster<'_> {
#[inline]
fn run_verifier<'o, 'b>(
v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<Vec3>(&"pos", Self::VT_POS, false)?
.visit_field::<i16>(&"mana", Self::VT_MANA, false)?
.visit_field::<i16>(&"hp", Self::VT_HP, false)?
.visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"name", Self::VT_NAME, false)?
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u8>>>(&"inventory", Self::VT_INVENTORY, false)?
.visit_field::<Color>(&"color", Self::VT_COLOR, false)?
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<Weapon>>>>(&"weapons", Self::VT_WEAPONS, false)?
.visit_union::<Equipment, _>(&"equipped_type", Self::VT_EQUIPPED_TYPE, &"equipped", Self::VT_EQUIPPED, false, |key, v, pos| {
match key {
Equipment::Weapon => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Weapon>>("Equipment::Weapon", pos),
_ => Ok(()),
}
})?
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, Vec3>>>(&"path", Self::VT_PATH, false)?
.finish();
Ok(())
}
}
pub struct MonsterArgs<'a> {
pub pos: Option<&'a Vec3>,
pub mana: i16,
@@ -512,6 +574,19 @@ impl<'a> Weapon<'a> {
}
}
impl flatbuffers::Verifiable for Weapon<'_> {
#[inline]
fn run_verifier<'o, 'b>(
v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"name", Self::VT_NAME, false)?
.visit_field::<i16>(&"damage", Self::VT_DAMAGE, false)?
.finish();
Ok(())
}
}
pub struct WeaponArgs<'a> {
pub name: Option<flatbuffers::WIPOffset<&'a str>>,
pub damage: i16,
@@ -562,15 +637,77 @@ impl std::fmt::Debug for Weapon<'_> {
}
}
#[inline]
#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
flatbuffers::get_root::<Monster<'a>>(buf)
unsafe { flatbuffers::root_unchecked::<Monster<'a>>(buf) }
}
#[inline]
#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_size_prefixed_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
flatbuffers::get_size_prefixed_root::<Monster<'a>>(buf)
unsafe { flatbuffers::size_prefixed_root_unchecked::<Monster<'a>>(buf) }
}
#[inline]
/// Verifies that a buffer of bytes contains a `Monster`
/// and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_monster_unchecked`.
pub fn root_as_monster(buf: &[u8]) -> Result<Monster, flatbuffers::InvalidFlatbuffer> {
flatbuffers::root::<Monster>(buf)
}
#[inline]
/// Verifies that a buffer of bytes contains a size prefixed
/// `Monster` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `size_prefixed_root_as_monster_unchecked`.
pub fn size_prefixed_root_as_monster(buf: &[u8]) -> Result<Monster, flatbuffers::InvalidFlatbuffer> {
flatbuffers::size_prefixed_root::<Monster>(buf)
}
#[inline]
/// Verifies, with the given options, that a buffer of bytes
/// contains a `Monster` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_monster_unchecked`.
pub fn root_as_monster_with_opts<'b, 'o>(
opts: &'o flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Monster<'b>, flatbuffers::InvalidFlatbuffer> {
flatbuffers::root_with_opts::<Monster<'b>>(opts, buf)
}
#[inline]
/// Verifies, with the given verifier options, that a buffer of
/// bytes contains a size prefixed `Monster` and returns
/// it. Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_monster_unchecked`.
pub fn size_prefixed_root_as_monster_with_opts<'b, 'o>(
opts: &'o flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Monster<'b>, flatbuffers::InvalidFlatbuffer> {
flatbuffers::size_prefixed_root_with_opts::<Monster<'b>>(opts, buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a Monster and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `Monster`.
pub unsafe fn root_as_monster_unchecked(buf: &[u8]) -> Monster {
flatbuffers::root_unchecked::<Monster>(buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed Monster and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `Monster`.
pub unsafe fn size_prefixed_root_as_monster_unchecked(buf: &[u8]) -> Monster {
flatbuffers::size_prefixed_root_unchecked::<Monster>(buf)
}
#[inline]
pub fn finish_monster_buffer<'a, 'b>(
fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,

View File

@@ -20,8 +20,7 @@ extern crate flatbuffers;
// import the generated code
#[path = "./monster_generated.rs"]
mod monster_generated;
pub use monster_generated::my_game::sample::{get_root_as_monster,
Color, Equipment,
pub use monster_generated::my_game::sample::{Color, Equipment,
Monster, MonsterArgs,
Vec3,
Weapon, WeaponArgs};
@@ -98,7 +97,7 @@ fn main() {
let buf = builder.finished_data(); // Of type `&[u8]`
// Get access to the root:
let monster = get_root_as_monster(buf);
let monster = flatbuffers::root::<Monster>(buf).unwrap();
// Get and test some scalar types from the FlatBuffer.
let hp = monster.hp();