diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 53e48d590..4f797cbdb 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -81,6 +81,18 @@ inline SizeT GetPrefixedSize(const uint8_t *buf) { return ReadScalar(buf); } +// Gets the total length of the buffer given a sized prefixed FlatBuffer. +// +// This includes the size of the prefix as well as the buffer: +// +// [size prefix][flatbuffer] +// |---------length--------| +template +inline SizeT GetSizePrefixedBufferLength(const uint8_t * const buf) { + return ReadScalar(buf) + sizeof(SizeT); +} + + // Base class for native objects (FlatBuffer data de-serialized into native // C++ data structures). // Contains no functionality, purely documentative. diff --git a/include/flatbuffers/verifier.h b/include/flatbuffers/verifier.h index c64737e49..de1146be9 100644 --- a/include/flatbuffers/verifier.h +++ b/include/flatbuffers/verifier.h @@ -177,8 +177,8 @@ class Verifier FLATBUFFERS_FINAL_CLASS { return true; } - FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow") bool VerifyTableStart( - const uint8_t *const table) { + FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow") + bool VerifyTableStart(const uint8_t *const table) { // Check the vtable offset. const auto tableo = static_cast(table - buf_); if (!Verify(tableo)) return false; @@ -246,7 +246,9 @@ class Verifier FLATBUFFERS_FINAL_CLASS { template bool VerifySizePrefixedBuffer(const char *const identifier) { return Verify(0U) && - Check(ReadScalar(buf_) == size_ - sizeof(SizeT)) && + // Ensure the prefixed size is within the bounds of the provided + // length. + Check(ReadScalar(buf_) + sizeof(SizeT) <= size_) && VerifyBufferFromStart(identifier, sizeof(SizeT)); } diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index 2ca3277a9..d44f118ea 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -3,7 +3,9 @@ #include #include +#include "flatbuffers/base.h" #include "flatbuffers/flatbuffer_builder.h" +#include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/registry.h" #include "flatbuffers/verifier.h" @@ -422,8 +424,8 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { // Mutate structs. auto pos = monster->mutable_pos(); - auto & test3 = pos->mutable_test3(); // Struct inside a struct. - test3.mutate_a(50); // Struct fields never fail. + auto &test3 = pos->mutable_test3(); // Struct inside a struct. + test3.mutate_a(50); // Struct fields never fail. TEST_EQ(test3.a(), 50); test3.mutate_a(10); @@ -441,13 +443,12 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { first->mutate_hp(1000); // Test for each loop over mutable entries - for (auto item: *tables) - { + for (auto item : *tables) { TEST_EQ(item->hp(), 1000); item->mutate_hp(0); TEST_EQ(item->hp(), 0); item->mutate_hp(1000); - break; // one iteration is enough, just testing compilation + break; // one iteration is enough, just testing compilation } // Mutate via LookupByKey @@ -579,11 +580,31 @@ void SizePrefixedTest() { flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize()); TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true); + // The prefixed size doesn't include itself, so substract the size of the + // prefix + TEST_EQ(GetPrefixedSize(fbb.GetBufferPointer()), + fbb.GetSize() - sizeof(uoffset_t)); + + // Getting the buffer length does include the prefix size, so it should be the + // full lenght. + TEST_EQ(GetSizePrefixedBufferLength(fbb.GetBufferPointer()), fbb.GetSize()); + // Access it. auto m = GetSizePrefixedMonster(fbb.GetBufferPointer()); TEST_EQ(m->mana(), 200); TEST_EQ(m->hp(), 300); TEST_EQ_STR(m->name()->c_str(), "bob"); + + { + // Verify that passing a larger size is OK, but not a smaller + flatbuffers::Verifier verifier_larger(fbb.GetBufferPointer(), + fbb.GetSize() + 10); + TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier_larger), true); + + flatbuffers::Verifier verifier_smaller(fbb.GetBufferPointer(), + fbb.GetSize() - 10); + TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier_smaller), false); + } } void TestMonsterExtraFloats(const std::string &tests_data_path) {