diff options
author | Vladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com> | 2021-01-05 03:33:31 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-04 12:33:31 -0800 |
commit | e7430bbebd413b7d9f9a9a156c9c36ba80411580 (patch) | |
tree | 926d0e490efc43c64423798b32c155ff0722dcb1 | |
parent | 24dd85fd28b002d1dc6bca331b3e9516ea55c8cf (diff) | |
download | flatbuffers-e7430bbebd413b7d9f9a9a156c9c36ba80411580.tar.gz flatbuffers-e7430bbebd413b7d9f9a9a156c9c36ba80411580.tar.bz2 flatbuffers-e7430bbebd413b7d9f9a9a156c9c36ba80411580.zip |
[idl_parser] Check the range of explicitly set field's id value (#6363)
* [idl_parser] Check the range of explicitly set field's id value
The explicitly set `id` attribute should be a non-negative value of the `voffset_t` type.
* Format FieldIdentifierTest()
-rw-r--r-- | src/idl_parser.cpp | 43 | ||||
-rw-r--r-- | tests/test.cpp | 19 |
2 files changed, 53 insertions, 9 deletions
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 015a7112..77dbbafe 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -936,11 +936,22 @@ CheckedError Parser::ParseField(StructDef &struct_def) { // the automatically added type field should have an id as well (of N - 1). auto attr = field->attributes.Lookup("id"); if (attr) { - auto id = atoi(attr->constant.c_str()); - auto val = new Value(); - val->type = attr->type; - val->constant = NumToString(id - 1); - typefield->attributes.Add("id", val); + const auto &id_str = attr->constant; + voffset_t id = 0; + const auto done = !atot(id_str.c_str(), *this, &id).Check(); + if (done && id > 0) { + auto val = new Value(); + val->type = attr->type; + val->constant = NumToString(id - 1); + typefield->attributes.Add("id", val); + } else { + return Error( + "a union type effectively adds two fields with non-negative ids, " + "its id must be that of the second field (the first field is " + "the type field and not explicitly declared in the schema);\n" + "field: " + + field->name + ", id: " + id_str); + } } // if this field is a union that is deprecated, // the automatically added type field should be deprecated as well @@ -2410,11 +2421,25 @@ CheckedError Parser::ParseDecl() { // been specified. std::sort(fields.begin(), fields.end(), compareFieldDefs); // Verify we have a contiguous set, and reassign vtable offsets. - for (int i = 0; i < static_cast<int>(fields.size()); i++) { - if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str())) + FLATBUFFERS_ASSERT(fields.size() <= + flatbuffers::numeric_limits<voffset_t>::max()); + for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) { + auto &field = *fields[i]; + const auto &id_str = field.attributes.Lookup("id")->constant; + // Metadata values have a dynamic type, they can be `float`, 'int', or + // 'string`. + // The FieldIndexToOffset(i) expects the voffset_t so `id` is limited by + // this type. + voffset_t id = 0; + const auto done = !atot(id_str.c_str(), *this, &id).Check(); + if (!done) + return Error("field id\'s must be non-negative number, field: " + + field.name + ", id: " + id_str); + if (i != id) return Error("field id\'s must be consecutive from 0, id " + - NumToString(i) + " missing or set twice"); - fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i)); + NumToString(i) + " missing or set twice, field: " + + field.name + ", id: " + id_str); + field.value.offset = FieldIndexToOffset(i); } } } diff --git a/tests/test.cpp b/tests/test.cpp index bc0ca88c..13067bbe 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -3710,6 +3710,24 @@ void ParseFlexbuffersFromJsonWithNullTest() { } } +void FieldIdentifierTest() { + using flatbuffers::Parser; + TEST_EQ(true, Parser().Parse("table T{ f: int (id:0); }")); + // non-integer `id` should be rejected + TEST_EQ(false, Parser().Parse("table T{ f: int (id:text); }")); + TEST_EQ(false, Parser().Parse("table T{ f: int (id:\"text\"); }")); + TEST_EQ(false, Parser().Parse("table T{ f: int (id:0text); }")); + TEST_EQ(false, Parser().Parse("table T{ f: int (id:1.0); }")); + TEST_EQ(false, Parser().Parse("table T{ f: int (id:-1); g: int (id:0); }")); + TEST_EQ(false, Parser().Parse("table T{ f: int (id:129496726); }")); + // A unuion filed occupys two ids: enumerator + pointer (offset). + TEST_EQ(false, + Parser().Parse("union X{} table T{ u: X(id:0); table F{x:int;\n}")); + // Positive tests for unions + TEST_EQ(true, Parser().Parse("union X{} table T{ u: X (id:1); }")); + TEST_EQ(true, Parser().Parse("union X{} table T{ u: X; }")); +} + int FlatBufferTests() { // clang-format off @@ -3802,6 +3820,7 @@ int FlatBufferTests() { ParseFlexbuffersFromJsonWithNullTest(); FlatbuffersSpanTest(); FixedLengthArrayConstructorTest(); + FieldIdentifierTest(); return 0; } |