summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/flatbuffers/flatbuffers.h5
-rw-r--r--src/reflection.cpp99
-rw-r--r--tests/test.cpp12
3 files changed, 78 insertions, 38 deletions
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index 00593d6a..46457bd3 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -2109,6 +2109,11 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
return VerifyAlignment<T>(elem) && Verify(elem, sizeof(T));
}
+ bool VerifyFromPointer(const uint8_t *p, size_t len) {
+ auto o = static_cast<size_t>(p - buf_);
+ return Verify(o, len);
+ }
+
// Verify relative to a known-good base pointer.
bool Verify(const uint8_t *base, voffset_t elem_off, size_t elem_len) const {
return Verify(static_cast<size_t>(base - buf_) + elem_off, elem_len);
diff --git a/src/reflection.cpp b/src/reflection.cpp
index 5055959a..fc211c5f 100644
--- a/src/reflection.cpp
+++ b/src/reflection.cpp
@@ -515,6 +515,32 @@ bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
const reflection::Object &obj,
const flatbuffers::Table *table, bool required);
+bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ uint8_t utype, const uint8_t *elem,
+ const reflection::Field &union_field) {
+ if (!utype) return true; // Not present.
+ auto fb_enum = schema.enums()->Get(union_field.type()->index());
+ if (utype >= fb_enum->values()->size()) return false;
+ auto elem_type = fb_enum->values()->Get(utype)->union_type();
+ switch (elem_type->base_type()) {
+ case reflection::Obj: {
+ auto elem_obj = schema.objects()->Get(elem_type->index());
+ if (elem_obj->is_struct()) {
+ return v.VerifyFromPointer(elem, elem_obj->bytesize());
+ } else {
+ return VerifyObject(v, schema, *elem_obj,
+ reinterpret_cast<const flatbuffers::Table *>(elem),
+ true);
+ }
+ }
+ case reflection::String:
+ return v.VerifyString(
+ reinterpret_cast<const flatbuffers::String *>(elem));
+ default:
+ return false;
+ }
+}
+
bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
const flatbuffers::Table &table,
const reflection::Field &vec_field) {
@@ -522,7 +548,6 @@ bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false;
switch (vec_field.type()->element()) {
- case reflection::None: FLATBUFFERS_ASSERT(false); break;
case reflection::UType:
return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
case reflection::Bool:
@@ -552,48 +577,55 @@ bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
return false;
}
}
- case reflection::Vector: FLATBUFFERS_ASSERT(false); break;
case reflection::Obj: {
auto obj = schema.objects()->Get(vec_field.type()->index());
if (obj->is_struct()) {
- if (!VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
- vec_field.required())) {
- return false;
- }
+ return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
+ vec_field.required());
} else {
auto vec =
flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
table, vec_field);
if (!v.VerifyVector(vec)) return false;
- if (vec) {
- for (uoffset_t j = 0; j < vec->size(); j++) {
- if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
- return false;
- }
+ if (!vec) return true;
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
+ return false;
}
}
+ return true;
+ }
+ }
+ case reflection::Union: {
+ auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>(table,
+ vec_field);
+ if (!v.VerifyVector(vec)) return false;
+ if (!vec) return true;
+ auto type_vec = table.GetPointer<Vector<uint8_t> *>
+ (vec_field.offset() - sizeof(voffset_t));
+ if (!v.VerifyVector(type_vec)) return false;
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ // get union type from the prev field
+ auto utype = type_vec->Get(j);
+ auto elem = vec->Get(j);
+ if (!VerifyUnion(v, schema, utype, elem, vec_field))
+ return false;
}
return true;
}
- case reflection::Union: FLATBUFFERS_ASSERT(false); break;
- default: FLATBUFFERS_ASSERT(false); break;
+ case reflection::Vector:
+ case reflection::None:
+ default:
+ FLATBUFFERS_ASSERT(false);
+ return false;
}
-
- return false;
}
bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
const reflection::Object &obj,
const flatbuffers::Table *table, bool required) {
- if (!table) {
- if (!required)
- return true;
- else
- return false;
- }
-
+ if (!table) return !required;
if (!table->VerifyTableStart(v)) return false;
-
for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
auto field_def = obj.fields()->Get(i);
switch (field_def->type()->base_type()) {
@@ -631,7 +663,8 @@ bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
}
break;
case reflection::Vector:
- if (!VerifyVector(v, schema, *table, *field_def)) return false;
+ if (!VerifyVector(v, schema, *table, *field_def))
+ return false;
break;
case reflection::Obj: {
auto child_obj = schema.objects()->Get(field_def->type()->index());
@@ -653,20 +686,16 @@ bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
// get union type from the prev field
voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
auto utype = table->GetField<uint8_t>(utype_offset, 0);
- if (utype != 0) {
- // Means we have this union field present
- auto fb_enum = schema.enums()->Get(field_def->type()->index());
- if (utype >= fb_enum->values()->size()) return false;
- auto child_obj = fb_enum->values()->Get(utype)->object();
- if (!VerifyObject(v, schema, *child_obj,
- flatbuffers::GetFieldT(*table, *field_def),
- field_def->required())) {
- return false;
- }
+ auto uval = reinterpret_cast<const uint8_t *>(
+ flatbuffers::GetFieldT(*table, *field_def));
+ if (!VerifyUnion(v, schema, utype, uval, *field_def)) {
+ return false;
}
break;
}
- default: FLATBUFFERS_ASSERT(false); break;
+ default:
+ FLATBUFFERS_ASSERT(false);
+ break;
}
}
diff --git a/tests/test.cpp b/tests/test.cpp
index dfa0d6ab..939550db 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -2348,12 +2348,11 @@ void UnionVectorTest() {
fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
fbb.CreateVector(types), fbb.CreateVector(characters));
FinishMovieBuffer(fbb, movie_offset);
- auto buf = fbb.GetBufferPointer();
- flatbuffers::Verifier verifier(buf, fbb.GetSize());
+ flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
TEST_EQ(VerifyMovieBuffer(verifier), true);
- auto flat_movie = GetMovie(buf);
+ auto flat_movie = GetMovie(fbb.GetBufferPointer());
auto TestMovie = [](const Movie *movie) {
TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
@@ -2485,6 +2484,13 @@ void UnionVectorTest() {
" ]\n"
"}\n");
+ // Simple test with reflection.
+ parser.Serialize();
+ auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
+ auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
+ fbb.GetBufferPointer(), fbb.GetSize());
+ TEST_EQ(ok, true);
+
flatbuffers::Parser parser2(idl_opts);
TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
"union Any { Bool }"