diff --git a/src/reflection.cpp b/src/reflection.cpp index 268d7d851..904b7bcf0 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -36,6 +36,7 @@ static bool VerifyStruct(flatbuffers::Verifier& v, const flatbuffers::Table& parent_table, voffset_t field_offset, const reflection::Object& obj, bool required) { + if (obj.bytesize() <= 0 || obj.minalign() <= 0) return false; auto offset = parent_table.GetOptionalFieldOffset(field_offset); if (required && !offset) { return false; @@ -51,6 +52,7 @@ static bool VerifyVectorOfStructs(flatbuffers::Verifier& v, voffset_t field_offset, const reflection::Object& obj, bool required) { + if (obj.bytesize() <= 0 || obj.minalign() <= 0) return false; auto p = parent_table.GetPointer(field_offset); if (required && !p) { return false; @@ -156,6 +158,7 @@ static bool VerifyVector(flatbuffers::Verifier& v, auto type_vec = table.GetPointer*>(vec_field.offset() - sizeof(voffset_t)); if (!v.VerifyVector(type_vec)) return false; + if (!type_vec) return false; if (type_vec->size() != vec->size()) return false; for (uoffset_t j = 0; j < vec->size(); j++) { // get union type from the prev field diff --git a/tests/reflection_test.cpp b/tests/reflection_test.cpp index 9f80b936c..f10ca065e 100644 --- a/tests/reflection_test.cpp +++ b/tests/reflection_test.cpp @@ -9,13 +9,149 @@ #include "test_assert.h" #include "tests/arrays_test_generated.h" +#include + namespace flatbuffers { namespace tests { using namespace MyGame::Example; +namespace { + +Offset CreateEmptyTable(FlatBufferBuilder& fbb) { + auto start = fbb.StartTable(); + return Offset
(fbb.EndTable(start)); +} + +Offset CreateReflectionObject( + FlatBufferBuilder& fbb, const char* name, + Offset>> fields, bool is_struct = false, + int minalign = 0, int bytesize = 0) { + return reflection::CreateObject(fbb, fbb.CreateString(name), fields, + is_struct, minalign, bytesize, 0, 0, 0); +} + +std::vector BuilderBuffer(FlatBufferBuilder& fbb) { + return std::vector(fbb.GetBufferPointer(), + fbb.GetBufferPointer() + fbb.GetSize()); +} + +std::vector BuildUnionVectorSchema() { + FlatBufferBuilder fbb; + + auto none_type = reflection::CreateType(fbb, reflection::BaseType::None); + auto utype_type = reflection::CreateType(fbb, reflection::BaseType::UType); + auto item_type = reflection::CreateType( + fbb, reflection::BaseType::Obj, reflection::BaseType::None, 0); + auto vector_union_type = reflection::CreateType( + fbb, reflection::BaseType::Vector, reflection::BaseType::Union, 0); + + std::vector> enum_vals; + enum_vals.push_back( + reflection::CreateEnumVal(fbb, fbb.CreateString("NONE"), 0, none_type)); + enum_vals.push_back( + reflection::CreateEnumVal(fbb, fbb.CreateString("Item"), 1, item_type)); + auto enum_values = fbb.CreateVector(enum_vals); + auto enum_def = reflection::CreateEnum(fbb, fbb.CreateString("Any"), + enum_values, true, utype_type); + std::vector> enums = {enum_def}; + + auto empty_fields = fbb.CreateVector(std::vector>{}); + auto item_obj = CreateReflectionObject(fbb, "Item", empty_fields); + + std::vector> root_fields; + root_fields.push_back(reflection::CreateField( + fbb, fbb.CreateString("items"), vector_union_type, 1, 6)); + auto root_fields_vec = fbb.CreateVector(root_fields); + auto root_obj = CreateReflectionObject(fbb, "Root", root_fields_vec); + + std::vector> objects = {item_obj, root_obj}; + auto schema = reflection::CreateSchema(fbb, fbb.CreateVector(objects), + fbb.CreateVector(enums), 0, 0, + root_obj); + fbb.Finish(schema, reflection::SchemaIdentifier()); + return BuilderBuffer(fbb); +} + +std::vector BuildUnionVectorMissingTypesData() { + FlatBufferBuilder fbb; + auto item = CreateEmptyTable(fbb); + std::vector> items = {item}; + auto items_vec = fbb.CreateVector(items); + auto root_start = fbb.StartTable(); + fbb.AddOffset(6, items_vec); + auto root = Offset
(fbb.EndTable(root_start)); + fbb.Finish(root); + return BuilderBuffer(fbb); +} + +std::vector BuildZeroSizedStructVectorSchema() { + FlatBufferBuilder fbb; + + auto struct_vector_type = reflection::CreateType( + fbb, reflection::BaseType::Vector, reflection::BaseType::Obj, 0); + + auto empty_fields = fbb.CreateVector(std::vector>{}); + auto zero_struct = + CreateReflectionObject(fbb, "Zero", empty_fields, true, 1, 0); + + std::vector> root_fields; + root_fields.push_back(reflection::CreateField( + fbb, fbb.CreateString("items"), struct_vector_type, 0, 4)); + auto root_fields_vec = fbb.CreateVector(root_fields); + auto root_obj = CreateReflectionObject(fbb, "Root", root_fields_vec); + + std::vector> objects = {zero_struct, root_obj}; + std::vector> enums; + auto schema = reflection::CreateSchema(fbb, fbb.CreateVector(objects), + fbb.CreateVector(enums), 0, 0, + root_obj); + fbb.Finish(schema, reflection::SchemaIdentifier()); + return BuilderBuffer(fbb); +} + +std::vector BuildEmptyVectorData() { + FlatBufferBuilder fbb; + std::vector empty; + auto vec = fbb.CreateVector(empty); + auto root_start = fbb.StartTable(); + fbb.AddOffset(4, vec); + auto root = Offset
(fbb.EndTable(root_start)); + fbb.Finish(root); + return BuilderBuffer(fbb); +} + +void ReflectionVerifierRejectsMalformedUnionVector() { + auto schema_buffer = BuildUnionVectorSchema(); + Verifier schema_verifier(schema_buffer.data(), schema_buffer.size()); + TEST_EQ(reflection::VerifySchemaBuffer(schema_verifier), true); + auto schema = reflection::GetSchema(schema_buffer.data()); + + auto data = BuildUnionVectorMissingTypesData(); + TEST_EQ(flatbuffers::Verify(*schema, *schema->root_table(), data.data(), + data.size()), + false); +} + +void ReflectionVerifierRejectsZeroSizedStructVector() { + auto schema_buffer = BuildZeroSizedStructVectorSchema(); + Verifier schema_verifier(schema_buffer.data(), schema_buffer.size()); + TEST_EQ(reflection::VerifySchemaBuffer(schema_verifier), true); + auto schema = reflection::GetSchema(schema_buffer.data()); + + auto data = BuildEmptyVectorData(); + TEST_EQ(flatbuffers::Verify(*schema, *schema->root_table(), data.data(), + data.size()), + false); +} + +} // namespace + void ReflectionTest(const std::string& tests_data_path, uint8_t* flatbuf, size_t length) { + ReflectionVerifierRejectsMalformedUnionVector(); + ReflectionVerifierRejectsZeroSizedStructVector(); + // Load a binary schema. std::string bfbsfile; TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.bfbs").c_str(),