Define minimum buffer size (#7440)

* add check for zero sized buffers

* Define minimum flatbuffer size
diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h
index bb10db8..57b613f 100644
--- a/include/flatbuffers/base.h
+++ b/include/flatbuffers/base.h
@@ -331,6 +331,13 @@
 // In 32bits, this evaluates to 2GB - 1
 #define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1)
 
+// The minimum size buffer that can be a valid flatbuffer.
+// Includes the offset to the root table (uoffset_t), the offset to the vtable
+// of the root table (soffset_t), the size of the vtable (uint16_t), and the
+// size of the referring table (uint16_t).
+#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(uoffset_t) + sizeof(soffset_t) + \
+   sizeof(uint16_t) + sizeof(uint16_t)
+
 // We support aligning the contents of buffers up to this size.
 #ifndef FLATBUFFERS_MAX_ALIGNMENT
   #define FLATBUFFERS_MAX_ALIGNMENT 32
diff --git a/include/flatbuffers/verifier.h b/include/flatbuffers/verifier.h
index dd46dcf..0241223 100644
--- a/include/flatbuffers/verifier.h
+++ b/include/flatbuffers/verifier.h
@@ -178,6 +178,12 @@
 
   template<typename T>
   bool VerifyBufferFromStart(const char *const identifier, const size_t start) {
+    // Buffers have to be of some size to be valid. The reason it is a runtime
+    // check instead of static_assert, is that nested flatbuffers go through
+    // this call and their size is determined at runtime.
+    if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
+
+    // If an identifier is provided, check that we have a buffer
     if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
                               BufferHasIdentifier(buf_ + start, identifier)))) {
       return false;
@@ -198,7 +204,12 @@
   template<typename T>
   bool VerifyNestedFlatBuffer(const Vector<uint8_t> *const buf,
                               const char *const identifier) {
+    // An empty buffer is OK as it indicates not present.
     if (!buf) return true;
+
+    // If there is a nested buffer, it must be greater than the min size.
+    if(!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
+
     Verifier nested_verifier(buf->data(), buf->size());
     return nested_verifier.VerifyBuffer<T>(identifier);
   }
diff --git a/tests/test.cpp b/tests/test.cpp
index e7a906e..97c808a 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -4340,6 +4340,28 @@
                                    builder.GetSize());
     TEST_EQ(false, VerifyMonsterBuffer(verifier));
   }
+
+  {
+    // Create the outer monster.
+    flatbuffers::FlatBufferBuilder builder;
+
+    // Purposely invalidate the nested flatbuffer setting its length to 0, an
+    // invalid length.
+    uint8_t *invalid_nested_buffer = nullptr;
+    auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 0);
+
+    auto name = builder.CreateString("OuterMonster");
+
+    MonsterBuilder mon_builder(builder);
+    mon_builder.add_name(name);
+    mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
+    FinishMonsterBuffer(builder, mon_builder.Finish());
+
+    // Verify the root monster fails, since the included nested monster fails.
+    flatbuffers::Verifier verifier(builder.GetBufferPointer(),
+                                   builder.GetSize());
+    TEST_EQ(false, VerifyMonsterBuffer(verifier));
+  }
 }
 
 void ParseIncorrectMonsterJsonTest() {