Add support for Flatbuffers with 64-bit offsets. This change updates the Flatbuffers domain implementation to use flatbuffers::FlatBufferBuilder64 and handle 64-bit offsets where appropriate, based on the reflection schema. A new test case is added to verify round-trip functionality for a Flatbuffer schema using 64-bit offsets. PiperOrigin-RevId: 930534503
diff --git a/domain_tests/arbitrary_domains_flatbuffers_test.cc b/domain_tests/arbitrary_domains_flatbuffers_test.cc index 508ad26..d96c24d 100644 --- a/domain_tests/arbitrary_domains_flatbuffers_test.cc +++ b/domain_tests/arbitrary_domains_flatbuffers_test.cc
@@ -36,6 +36,7 @@ #include "./domain_tests/domain_testing.h" #include "./fuzztest/flatbuffers.h" #include "./fuzztest/internal/meta.h" +#include "./fuzztest/internal/test_flatbuffers_64bits_generated.h" #include "./fuzztest/internal/test_flatbuffers_generated.h" namespace fuzztest { @@ -43,6 +44,7 @@ using ::fuzztest::internal::BoolTable; using ::fuzztest::internal::DefaultTable; +using ::fuzztest::internal::DefaultTable64; using ::fuzztest::internal::OptionalTable; using ::fuzztest::internal::RecursiveTable; using ::fuzztest::internal::RequiredTable; @@ -592,5 +594,29 @@ ASSERT_THAT(new_table, IsNull()); } +TEST(FlatbuffersTableDomainImplTest, DefaultTable64ValueRoundTrip) { + flatbuffers::FlatBufferBuilder64 fbb; + auto str_offset = fbb.CreateString<flatbuffers::Offset64>("foo bar baz"); + auto table_offset = internal::CreateDefaultTable64(fbb, str_offset); + fbb.Finish(table_offset); + auto table = flatbuffers::GetRoot<DefaultTable64>(fbb.GetBufferPointer()); + + auto domain = Arbitrary<const DefaultTable64*>(); + auto corpus = domain.FromValue(table); + ASSERT_TRUE(corpus.has_value()); + ASSERT_OK(domain.ValidateCorpusValue(*corpus)); + + auto ir = domain.SerializeCorpus(corpus.value()); + + auto new_corpus = domain.ParseCorpus(ir); + ASSERT_TRUE(new_corpus.has_value()); + ASSERT_OK(domain.ValidateCorpusValue(*new_corpus)); + + auto new_table = domain.GetValue(*new_corpus); + ASSERT_THAT(new_table, NotNull()); + ASSERT_THAT(new_table->str(), NotNull()); + EXPECT_EQ(new_table->str()->str(), "foo bar baz"); +} + } // namespace } // namespace fuzztest
diff --git a/fuzztest/internal/BUILD b/fuzztest/internal/BUILD index f515591..2bf470f 100644 --- a/fuzztest/internal/BUILD +++ b/fuzztest/internal/BUILD
@@ -616,8 +616,13 @@ flatbuffer_library_public( name = "test_flatbuffers_fbs", - srcs = ["test_flatbuffers.fbs"], + srcs = [ + "test_flatbuffers.fbs", + "test_flatbuffers_64bits.fbs", + ], outs = [ + "test_flatbuffers_64bits_bfbs_generated.h", + "test_flatbuffers_64bits_generated.h", "test_flatbuffers_bfbs_generated.h", "test_flatbuffers_generated.h", ],
diff --git a/fuzztest/internal/CMakeLists.txt b/fuzztest/internal/CMakeLists.txt index 0eb75ab..5c1173e 100644 --- a/fuzztest/internal/CMakeLists.txt +++ b/fuzztest/internal/CMakeLists.txt
@@ -574,6 +574,7 @@ test_flatbuffers_headers SCHEMAS "test_flatbuffers.fbs" + "test_flatbuffers_64bits.fbs" FLAGS --bfbs-gen-embed --gen-name-strings TESTONLY
diff --git a/fuzztest/internal/domains/flatbuffers_domain_impl.cc b/fuzztest/internal/domains/flatbuffers_domain_impl.cc index 7e8e144..9031344 100644 --- a/fuzztest/internal/domains/flatbuffers_domain_impl.cc +++ b/fuzztest/internal/domains/flatbuffers_domain_impl.cc
@@ -276,11 +276,11 @@ } uint32_t FlatbuffersTableUntypedDomainImpl::BuildTable( - const corpus_type& value, flatbuffers::FlatBufferBuilder& builder) const { + const corpus_type& value, flatbuffers::FlatBufferBuilder64& builder) const { // Add all the fields to the builder. // Offsets is the map of field id to its offset in the table. - absl::flat_hash_map<typename corpus_type::key_type, flatbuffers::uoffset_t> + absl::flat_hash_map<typename corpus_type::key_type, flatbuffers::uoffset64_t> offsets; // Some fields are stored inline in the flatbuffer table itself (a.k.a
diff --git a/fuzztest/internal/domains/flatbuffers_domain_impl.h b/fuzztest/internal/domains/flatbuffers_domain_impl.h index 1482a59..328b2e7 100644 --- a/fuzztest/internal/domains/flatbuffers_domain_impl.h +++ b/fuzztest/internal/domains/flatbuffers_domain_impl.h
@@ -37,6 +37,7 @@ #include "absl/strings/str_format.h" #include "absl/synchronization/mutex.h" #include "flatbuffers/base.h" +#include "flatbuffers/buffer.h" #include "flatbuffers/flatbuffer_builder.h" #include "flatbuffers/reflection_generated.h" #include "flatbuffers/string.h" @@ -365,7 +366,7 @@ bool IsSupportedField(const reflection::Field* absl_nonnull field) const; uint32_t BuildTable(const corpus_type& value, - flatbuffers::FlatBufferBuilder& builder) const; + flatbuffers::FlatBufferBuilder64& builder) const; // Returns the domain for the given field. // The domain is cached, and the same instance is returned for the same field. @@ -441,9 +442,15 @@ } } else if constexpr (std::is_same_v<T, std::string>) { if (user_value->CheckField(field->offset())) { - inner_value = std::optional( - user_value->GetPointer<flatbuffers::String*>(field->offset()) - ->str()); + if (field->offset64()) { + inner_value = std::optional( + user_value->GetPointer64<flatbuffers::String*>(field->offset()) + ->str()); + } else { + inner_value = std::optional( + user_value->GetPointer<flatbuffers::String*>(field->offset()) + ->str()); + } } } else if constexpr (std::is_same_v<T, FlatbuffersTableTag>) { auto sub_object = self.schema_->objects()->Get(field->type()->index()); @@ -464,9 +471,9 @@ // Create out-of-line table fields, see `BuildTable` for details. struct TableFieldBuilderVisitor { const FlatbuffersTableUntypedDomainImpl& self; - flatbuffers::FlatBufferBuilder& builder; - absl::flat_hash_map<typename corpus_type::key_type, flatbuffers::uoffset_t>& - offsets; + flatbuffers::FlatBufferBuilder64& builder; + absl::flat_hash_map<typename corpus_type::key_type, + flatbuffers::uoffset64_t>& offsets; const typename corpus_type::mapped_type& corpus_value; template <typename T> @@ -475,8 +482,16 @@ auto& domain = self.GetCachedDomain<T>(field); auto user_value = domain.GetValue(corpus_value); if (user_value.has_value()) { - auto offset = - builder.CreateString(user_value->data(), user_value->size()).o; + flatbuffers::uoffset64_t offset; + if (field->offset64()) { + offset = builder + .CreateString<flatbuffers::Offset64>( + user_value->data(), user_value->size()) + .o; + } else { + offset = + builder.CreateString(user_value->data(), user_value->size()).o; + } offsets.insert({field->id(), offset}); } } else if constexpr (std::is_same_v<T, FlatbuffersTableTag>) { @@ -502,9 +517,9 @@ // offsets for "out-of-line fields". See `BuildTable` for details. struct TableBuilderVisitor { const FlatbuffersTableUntypedDomainImpl& self; - flatbuffers::FlatBufferBuilder& builder; - const absl::flat_hash_map<typename corpus_type::key_type, - flatbuffers::uoffset_t>& offsets; + flatbuffers::FlatBufferBuilder64& builder; + absl::flat_hash_map<typename corpus_type::key_type, + flatbuffers::uoffset64_t>& offsets; const typename corpus_type::value_type::second_type& corpus_value; template <typename T> @@ -521,9 +536,15 @@ } else if constexpr (std::is_same_v<T, std::string>) { // "Out-of-line field". Store just offset. if (auto it = offsets.find(field->id()); it != offsets.end()) { - builder.AddOffset( - field->offset(), - flatbuffers::Offset<flatbuffers::String>(it->second)); + if (field->offset64()) { + builder.AddOffset( + field->offset(), + flatbuffers::Offset64<flatbuffers::String>(it->second)); + } else { + builder.AddOffset( + field->offset(), + flatbuffers::Offset<flatbuffers::String>(it->second)); + } } } else if constexpr (std::is_same_v<T, FlatbuffersTableTag>) { // "Out-of-line field". Store just offset. @@ -753,7 +774,7 @@ // Converts corpus value into the exact flatbuffer. value_type GetValue(const corpus_type& value) const { - flatbuffers::FlatBufferBuilder builder; + flatbuffers::FlatBufferBuilder64 builder; const uint32_t offset = inner_->BuildTable(value.untyped_corpus, builder); builder.Finish(flatbuffers::Offset<flatbuffers::Table>(offset)); value.buffer =
diff --git a/fuzztest/internal/test_flatbuffers_64bits.fbs b/fuzztest/internal/test_flatbuffers_64bits.fbs new file mode 100644 index 0000000..b893c88 --- /dev/null +++ b/fuzztest/internal/test_flatbuffers_64bits.fbs
@@ -0,0 +1,21 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace fuzztest.internal; + +table DefaultTable64 { + str:string (offset64); +} + +root_type DefaultTable64;