google/flatbuffers

[C++] : Issue with generated code when naked buffer on a field

Opened this issue · 0 comments

This issue includes the issue pointed to by #8144, but was never actually fixed upstream due to developer inactivity.

As such, I'm riving their issue, and expanding on it - I found another place where it was assumed the user would never use naked pointers in the object API.

Here was their original example:

static_assert( FLATBUFFERS_VERSION_MAJOR == 23 &&
               FLATBUFFERS_VERSION_MINOR == 5 &&
               FLATBUFFERS_VERSION_REVISION == 26,
               "Non-compatible flatbuffers version included" );

Given this simplified schema:

table A{

    field1: uint32;

}

table B {

    list : [A] (required, cpp_ptr_type:"naked");

}

root_type B;

The erronous code is produced here:

inline void B::UnPackTo ( BT *_o, const ::flatbuffers::resolver_function_t *_resolver ) const {
        (void)_o;
        (void)_resolver;
        {
                auto _e = list();

                if ( _e ){
                        _o->list.resize( _e->size() );

                        for ( ::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++ ){
                                if ( _o->list[_i] ){
                                        _e->Get( _i )->UnPackTo( _o->list[_i].get(), _resolver ); //here is the error : the .get()
                                }
                                else {
                                        _o->list[_i] = ( _e->Get( _i )->UnPack( _resolver ) );
                                }

                                ;
                        }
                }
                else {
                        _o->list.resize( 0 );
                }
        }
}

Additionally, defining just a field with a naked_ptr attribute on a circular table type can also result in erronous code:

table A{
  field1: B (cpp_ptr_type:"naked");
  field2: B (cpp_ptr_type:"naked");
}

table B {
   blah: uint;
}

root_type B;
inline void A::UnPackTo(AT*_o, const ::flatbuffers::resolver_function_t *_resolver) const {
  (void)_o;
  (void)_resolver;
  { auto _e = field1(); if (_e) { if(_o->field1) { _e->UnPackTo(_o->field1.get(), _resolver); } else { _o->field1 = (_e->UnPack(_resolver)); } } else if (_o->field1) { _o->field1.reset(); } } // Notice that .get() and .reset() are called
  { auto _e = field2(); if (_e) { if(_o->field2) { _e->UnPackTo(_o->field2.get(), _resolver); } else { _o->field2 = (_e->UnPack(_resolver)); } } else if (_o->field2) { _o->field2.reset(); } } // Notice that .get() and .reset() are called
}

In order to address this, I'm issuing a new PR that I will carry all the way through. The PR will include the fix from the included issue, as well as the fix for the second example.