Search code examples
rustcrashflatbufferspanic

How to check check if a Flatbuffer is valid or handle an error correctly?


I‘m using Rust and Flatbuffers to load files. When I try to load a file which is not a valid flatbuffer file, my program panics with an index out of range. How can I show a error to the user and not crash?

Small Example:

file_content_as_u8 // This is my &[u8] where I have loaded the file content.
// &[u8] to fltabuffer where get_root_as_file is generated by flatbuffer
let file_content = get_root_as_file(file_content_as_u8);
// Try to read data field from flatbuffer
let data = file_content.data();
// If file_content_as_u8 wasn't a valid flatbuffer file file_content.data()
// results in a panic with an index out of range

Solution

  • The code for get_root:

    #[inline]
    pub fn get_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
        <ForwardsUOffset<T>>::follow(data, 0)
    }
    

    The implementation for Follow for ForwardsUOffset:

    impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
        type Inner = T::Inner;
        #[inline(always)]
        fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
            let slice = &buf[loc..loc + SIZE_UOFFSET];
            let off = read_scalar::<u32>(slice) as usize;
            T::follow(buf, loc + off)
        }
    }
    

    This implementation does not do any bounds checking, interprets the first 4 bytes as an offset, and just calls follow on the part of the buffer pointed to by offset. I don't know what T is in your context, but if the file is smaller than 4 bytes, this code will panic with an index out of range. If it is not, a similar situation can happen in the implementation of T::follow, since there's no bounds checking in any of the follow implementations that I've seen, and follow returns a naked value, not Result.

    You have two options here:

    • Report the bug to the Flatbuffers developers, and get them to handle the corrupted files better.
    • Handle the panic yourself using std::panic::catch_unwind.

    Disclaimer: I work at Google, but I don't work on anything related to Flatbuffers.