google / flatbuffers

FlatBuffers: Memory Efficient Serialization Library
https://flatbuffers.dev/
Apache License 2.0
23.28k stars 3.25k forks source link

Bug in flatbuffers::CopyTable ? #3857

Closed facontidavide closed 8 years ago

facontidavide commented 8 years ago

I have been using the reflection functionalities and I eventually found some weird behavious.

What I do is: 1) Parse a schema from string/file. 2) build reflection::Schema. This oblige me to call parser.Serialize() first. 3) use CopyTable to build a "stripped" version of FlatBufferBuilder. 4) Write on the new builder.

Unfortunately the last step fails sometimes. It seems related to the way that CopyTable generate the copies into the new builder. the following code make the problem reproducible.

#include <stdio.h>
#include "flatbuffers/reflection.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"

void BuildFlatbufferAndModify(const std::string& schemafile )
{
    // parse schema first, so we can use it to parse the data after
    flatbuffers::Parser parser;

    bool ok = parser.Parse(schemafile.c_str(), nullptr, nullptr);
    assert(ok);

    // store the schema in parser.builder_
    parser.Serialize();

    // build reflection::Schema
    auto& schema = *reflection::GetSchema( parser.builder_.GetBufferPointer() );

    // next, we will use parser.builder_ as basis to create a new builder
    // I want the new builder to contain just the data, not the schema.
    uint8_t* flatbuf = parser.builder_.GetBufferPointer();

    flatbuffers::FlatBufferBuilder fbb;
    auto root = flatbuffers::GetAnyRoot( flatbuf );

    auto table_offset = flatbuffers::CopyTable(fbb,
                                          schema,
                                          *schema.root_table(),
                                          *root );
    fbb.Finish(table_offset);

    auto& table = *flatbuffers::GetAnyRoot( fbb.GetBufferPointer() );
    auto fields =  schema.root_table()->fields();

    for (unsigned i=0; i< fields->size(); i++ )  
   {
        auto field_ptr = fields->Get(i);
        auto &field = *field_ptr;

        if( ! flatbuffers::SetAnyFieldI( &table, field, 0X42) )   {
            printf("error writing field %s\n", field.name()->c_str() );
        }
    }

    // "dump" the flatbuffer
    for (unsigned a=0; a<fbb.GetSize(); a++ ) {
        printf("%02X ", fbb.GetBufferPointer()[a] );
    }
    printf("\n-----------\n");
}

int main(int , char **)
{
    std::string fbs_source_5 (
                 "table Test\n"
                 "{ \n"
                 "  a: int; "
                 "  b: int; "
                 "  c: int; "
                 "  d: int; "
                 "  e: int; "
                 "} \n"
                 "root_type Test; \n");

    std::string fbs_source_6 (
                 "table Test\n"
                 "{ \n"
                 "  a: int; "
                 "  b: int; "
                 "  c: int; "
                 "  d: int; "
                 "  e: int; "
                 "  f: int; "
                 "} \n"
                 "root_type Test; \n");

    BuildFlatbufferAndModify(fbs_source_5);
    BuildFlatbufferAndModify(fbs_source_6);

    return 0;
}
ghost commented 8 years ago

I already responded to this in a similar email on the google groups.