diff --git a/domain_tests/arbitrary_domains_flatbuffers_test.cc b/domain_tests/arbitrary_domains_flatbuffers_test.cc index 508ad269..d96c24dd 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 @@ namespace { 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 @@ TEST(FlatbuffersTableDomainImplTest, RecursiveTable) { ASSERT_THAT(new_table, IsNull()); } +TEST(FlatbuffersTableDomainImplTest, DefaultTable64ValueRoundTrip) { + flatbuffers::FlatBufferBuilder64 fbb; + auto str_offset = fbb.CreateString("foo bar baz"); + auto table_offset = internal::CreateDefaultTable64(fbb, str_offset); + fbb.Finish(table_offset); + auto table = flatbuffers::GetRoot(fbb.GetBufferPointer()); + + auto domain = Arbitrary(); + 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 f5155910..2bf470ff 100644 --- a/fuzztest/internal/BUILD +++ b/fuzztest/internal/BUILD @@ -616,8 +616,13 @@ cc_test( 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 0eb75aba..5c1173e6 100644 --- a/fuzztest/internal/CMakeLists.txt +++ b/fuzztest/internal/CMakeLists.txt @@ -574,6 +574,7 @@ if (FUZZTEST_BUILD_FLATBUFFERS) 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 7e8e144e..90313441 100644 --- a/fuzztest/internal/domains/flatbuffers_domain_impl.cc +++ b/fuzztest/internal/domains/flatbuffers_domain_impl.cc @@ -276,11 +276,11 @@ bool FlatbuffersTableUntypedDomainImpl::IsSupportedField( } 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 + absl::flat_hash_map 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 1482a598..328b2e7b 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 @@ class FlatbuffersTableUntypedDomainImpl 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 @@ class FlatbuffersTableUntypedDomainImpl } } else if constexpr (std::is_same_v) { if (user_value->CheckField(field->offset())) { - inner_value = std::optional( - user_value->GetPointer(field->offset()) - ->str()); + if (field->offset64()) { + inner_value = std::optional( + user_value->GetPointer64(field->offset()) + ->str()); + } else { + inner_value = std::optional( + user_value->GetPointer(field->offset()) + ->str()); + } } } else if constexpr (std::is_same_v) { auto sub_object = self.schema_->objects()->Get(field->type()->index()); @@ -464,9 +471,9 @@ class FlatbuffersTableUntypedDomainImpl // Create out-of-line table fields, see `BuildTable` for details. struct TableFieldBuilderVisitor { const FlatbuffersTableUntypedDomainImpl& self; - flatbuffers::FlatBufferBuilder& builder; - absl::flat_hash_map& - offsets; + flatbuffers::FlatBufferBuilder64& builder; + absl::flat_hash_map& offsets; const typename corpus_type::mapped_type& corpus_value; template @@ -475,8 +482,16 @@ class FlatbuffersTableUntypedDomainImpl auto& domain = self.GetCachedDomain(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( + 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) { @@ -502,9 +517,9 @@ class FlatbuffersTableUntypedDomainImpl // offsets for "out-of-line fields". See `BuildTable` for details. struct TableBuilderVisitor { const FlatbuffersTableUntypedDomainImpl& self; - flatbuffers::FlatBufferBuilder& builder; - const absl::flat_hash_map& offsets; + flatbuffers::FlatBufferBuilder64& builder; + absl::flat_hash_map& offsets; const typename corpus_type::value_type::second_type& corpus_value; template @@ -521,9 +536,15 @@ class FlatbuffersTableUntypedDomainImpl } else if constexpr (std::is_same_v) { // "Out-of-line field". Store just offset. if (auto it = offsets.find(field->id()); it != offsets.end()) { - builder.AddOffset( - field->offset(), - flatbuffers::Offset(it->second)); + if (field->offset64()) { + builder.AddOffset( + field->offset(), + flatbuffers::Offset64(it->second)); + } else { + builder.AddOffset( + field->offset(), + flatbuffers::Offset(it->second)); + } } } else if constexpr (std::is_same_v) { // "Out-of-line field". Store just offset. @@ -753,7 +774,7 @@ class FlatbuffersTableDomainImpl // 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(offset)); value.buffer = diff --git a/fuzztest/internal/test_flatbuffers_64bits.fbs b/fuzztest/internal/test_flatbuffers_64bits.fbs new file mode 100644 index 00000000..b893c887 --- /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;