mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-22 17:58:52 +00:00
Fixed reflection.h not modifying certain table configurations.
It would write 64bits offsets instead of 32bit ones, and update the vtable pointer before the fields were processed. Change-Id: I0c0fa942bbd3b42839294f5653ba8fa048612624 Tested: on Linux.
This commit is contained in:
@@ -356,7 +356,8 @@ public:
|
|||||||
void MutateOffset(uoffset_t i, const uint8_t *val) {
|
void MutateOffset(uoffset_t i, const uint8_t *val) {
|
||||||
assert(i < size());
|
assert(i < size());
|
||||||
assert(sizeof(T) == sizeof(uoffset_t));
|
assert(sizeof(T) == sizeof(uoffset_t));
|
||||||
WriteScalar(data() + i, val - (Data() + i * sizeof(uoffset_t)));
|
WriteScalar(data() + i,
|
||||||
|
static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a mutable pointer to tables/strings inside this vector.
|
// Get a mutable pointer to tables/strings inside this vector.
|
||||||
@@ -1495,7 +1496,8 @@ class Table {
|
|||||||
bool SetPointer(voffset_t field, const uint8_t *val) {
|
bool SetPointer(voffset_t field, const uint8_t *val) {
|
||||||
auto field_offset = GetOptionalFieldOffset(field);
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
if (!field_offset) return false;
|
if (!field_offset) return false;
|
||||||
WriteScalar(data_ + field_offset, val - (data_ + field_offset));
|
WriteScalar(data_ + field_offset,
|
||||||
|
static_cast<uoffset_t>(val - (data_ + field_offset)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -204,72 +204,76 @@ class ResizeContext {
|
|||||||
if (DagCheck(table))
|
if (DagCheck(table))
|
||||||
return; // Table already visited.
|
return; // Table already visited.
|
||||||
auto vtable = table->GetVTable();
|
auto vtable = table->GetVTable();
|
||||||
// Check if the vtable offset points beyond the insertion point.
|
|
||||||
Straddle<soffset_t, -1>(table, vtable, table);
|
|
||||||
// This direction shouldn't happen because vtables that sit before tables
|
|
||||||
// are always directly adjacent, but check just in case we ever change the
|
|
||||||
// way flatbuffers are built.
|
|
||||||
Straddle<soffset_t, -1>(vtable, table, table);
|
|
||||||
// Early out: since all fields inside the table must point forwards in
|
// Early out: since all fields inside the table must point forwards in
|
||||||
// memory, if the insertion point is before the table we can stop here.
|
// memory, if the insertion point is before the table we can stop here.
|
||||||
auto tableloc = reinterpret_cast<uint8_t *>(table);
|
auto tableloc = reinterpret_cast<uint8_t *>(table);
|
||||||
if (startptr_ <= tableloc) return;
|
if (startptr_ <= tableloc) {
|
||||||
// Check each field.
|
// Check if insertion point is between the table and a vtable that
|
||||||
auto fielddefs = objectdef.fields();
|
// precedes it. This can't happen in current construction code, but check
|
||||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
// just in case we ever change the way flatbuffers are built.
|
||||||
auto &fielddef = **it;
|
Straddle<soffset_t, -1>(vtable, table, table);
|
||||||
auto base_type = fielddef.type()->base_type();
|
} else {
|
||||||
// Ignore scalars.
|
// Check each field.
|
||||||
if (base_type <= reflection::Double) continue;
|
auto fielddefs = objectdef.fields();
|
||||||
// Ignore fields that are not stored.
|
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||||
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
|
auto &fielddef = **it;
|
||||||
if (!offset) continue;
|
auto base_type = fielddef.type()->base_type();
|
||||||
// Ignore structs.
|
// Ignore scalars.
|
||||||
auto subobjectdef = base_type == reflection::Obj ?
|
if (base_type <= reflection::Double) continue;
|
||||||
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
|
// Ignore fields that are not stored.
|
||||||
if (subobjectdef && subobjectdef->is_struct()) continue;
|
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
|
||||||
// Get this fields' offset, and read it if safe.
|
if (!offset) continue;
|
||||||
auto offsetloc = tableloc + offset;
|
// Ignore structs.
|
||||||
if (DagCheck(offsetloc))
|
auto subobjectdef = base_type == reflection::Obj ?
|
||||||
continue; // This offset already visited.
|
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
|
||||||
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
|
if (subobjectdef && subobjectdef->is_struct()) continue;
|
||||||
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
|
// Get this fields' offset, and read it if safe.
|
||||||
// Recurse.
|
auto offsetloc = tableloc + offset;
|
||||||
switch (base_type) {
|
if (DagCheck(offsetloc))
|
||||||
case reflection::Obj: {
|
continue; // This offset already visited.
|
||||||
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
|
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
|
||||||
break;
|
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
|
||||||
}
|
// Recurse.
|
||||||
case reflection::Vector: {
|
switch (base_type) {
|
||||||
auto elem_type = fielddef.type()->element();
|
case reflection::Obj: {
|
||||||
if (elem_type != reflection::Obj && elem_type != reflection::String)
|
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
|
||||||
break;
|
break;
|
||||||
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
|
|
||||||
auto elemobjectdef = elem_type == reflection::Obj
|
|
||||||
? schema_.objects()->Get(fielddef.type()->index())
|
|
||||||
: nullptr;
|
|
||||||
if (elemobjectdef && elemobjectdef->is_struct()) break;
|
|
||||||
for (uoffset_t i = 0; i < vec->size(); i++) {
|
|
||||||
auto loc = vec->Data() + i * sizeof(uoffset_t);
|
|
||||||
if (DagCheck(loc))
|
|
||||||
continue; // This offset already visited.
|
|
||||||
auto dest = loc + vec->Get(i);
|
|
||||||
Straddle<uoffset_t, 1>(loc, dest ,loc);
|
|
||||||
if (elemobjectdef)
|
|
||||||
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
|
|
||||||
}
|
}
|
||||||
break;
|
case reflection::Vector: {
|
||||||
|
auto elem_type = fielddef.type()->element();
|
||||||
|
if (elem_type != reflection::Obj && elem_type != reflection::String)
|
||||||
|
break;
|
||||||
|
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
|
||||||
|
auto elemobjectdef = elem_type == reflection::Obj
|
||||||
|
? schema_.objects()->Get(fielddef.type()->index())
|
||||||
|
: nullptr;
|
||||||
|
if (elemobjectdef && elemobjectdef->is_struct()) break;
|
||||||
|
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||||
|
auto loc = vec->Data() + i * sizeof(uoffset_t);
|
||||||
|
if (DagCheck(loc))
|
||||||
|
continue; // This offset already visited.
|
||||||
|
auto dest = loc + vec->Get(i);
|
||||||
|
Straddle<uoffset_t, 1>(loc, dest ,loc);
|
||||||
|
if (elemobjectdef)
|
||||||
|
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case reflection::Union: {
|
||||||
|
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
|
||||||
|
reinterpret_cast<Table *>(ref));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case reflection::String:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
case reflection::Union: {
|
|
||||||
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
|
|
||||||
reinterpret_cast<Table *>(ref));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case reflection::String:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
|
// Check if the vtable offset points beyond the insertion point.
|
||||||
|
// Must do this last, since GetOptionalFieldOffset above still reads
|
||||||
|
// this value.
|
||||||
|
Straddle<soffset_t, -1>(table, vtable, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user