Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rust] inconsistent nested_flatbuffers validations #8291

Open
Nekrolm opened this issue Apr 25, 2024 · 0 comments
Open

[Rust] inconsistent nested_flatbuffers validations #8291

Nekrolm opened this issue Apr 25, 2024 · 0 comments

Comments

@Nekrolm
Copy link

Nekrolm commented Apr 25, 2024

For byte fields marked as "nested_flatbuffer" flatc generates corresponding accessors

e.g. for schema

table Nested {
    value: string;
}

table Schema {
    nested: [ubyte] (nested_flatbuffer: "Nested");
}
root_type Schema;

the following safe accessor is generated

pub fn nested_nested_flatbuffer(&'a self) -> Option<Nested<'a>> {
    self.nested().map(|data| {
      use flatbuffers::Follow;
      // Safety:
      // Created from a valid Table for this object
      // Which contains a valid flatbuffer in this slot
      unsafe { <flatbuffers::ForwardsUOffset<Nested<'a>>>::follow(data.bytes(), 0) }
    })
  }

But assumption that the flatbuffer is valid there could be violated.
E.g. it is possible to create invalid utf-8 &str even if only safe API is used and it looks like the all necessary validations were made:

mod schema_generated;

use schema_generated as fb;

fn nested() -> Vec<u8> {
    let mut builder = flatbuffers::FlatBufferBuilder::new();
    let s = builder.create_string("world");
    let nested = fb::Nested::create(&mut builder, &fb::NestedArgs {
        value: Some(s)
    });
    builder.finish(nested, None);
    let mut data = builder.finished_data().to_vec();
    // some corruption happens
    data.last_chunk_mut::<6>().map(|c| c[1] = 0xff);
    data
}

fn main() {

    let mut builder = flatbuffers::FlatBufferBuilder::new();
    let bytes = builder.create_vector(&nested());
    let schema = fb::Schema::create(&mut builder, &fb::SchemaArgs {
        nested: Some(bytes)
    });
    builder.finish(schema, None);
    let data = builder.finished_data();

    let schema = fb::root_as_schema(data).expect("ok root");
    
    let nested = schema.nested().map(|n| flatbuffers::root::<fb::Nested>(n.bytes())).transpose();
    
    // validation failed -- ok, as expected
    let err = nested.expect_err("utf-8 error");
    println!("got error {err:?}");


    let nested = schema.nested_nested_flatbuffer().expect("ok, it's there");
    let value = nested.value();
    // and now it panics!
    println!("hello: {value:?}")
}

output with rustc-1.77 in release:

got error Utf8Error { error: Utf8Error { valid_up_to: 3, error_len: Some(1) }, range: 24..29, error_trace: ErrorTrace([TableField { field_name: "value", position: 16 }]) }
thread 'main' panicked at library/core/src/fmt/mod.rs:2350:34:
byte index 7 is out of bounds of `wor�d`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
// flatbuffers crate:
name = "flatbuffers"
version = "24.3.25"

flatbuffers/flatc --version
flatc version 24.3.25
@Nekrolm Nekrolm changed the title Rust: nested_flatbuffers validations Rust: inconsistent nested_flatbuffers validations Apr 25, 2024
@Nekrolm Nekrolm changed the title Rust: inconsistent nested_flatbuffers validations [Rust] inconsistent nested_flatbuffers validations Apr 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant