3737#include " absl/strings/str_format.h"
3838#include " absl/synchronization/mutex.h"
3939#include " flatbuffers/base.h"
40+ #include " flatbuffers/buffer.h"
4041#include " flatbuffers/flatbuffer_builder.h"
42+ #include " flatbuffers/reflection.h"
4143#include " flatbuffers/reflection_generated.h"
4244#include " flatbuffers/string.h"
4345#include " flatbuffers/table.h"
@@ -82,67 +84,80 @@ struct FlatbuffersStructTag;
8284struct FlatbuffersUnionTag ;
8385struct FlatbuffersVectorTag ;
8486
87+ // Helper to wrap the visitor with the correct tag type.
88+ template <template <typename > typename Wrapper, typename Visitor>
89+ struct VisitorTagWrapper {
90+ Visitor&& visitor;
91+ template <typename T>
92+ void Visit (const reflection::Field* absl_nonnull field) const {
93+ std::forward<Visitor>(visitor).template Visit <Wrapper<T>>(field);
94+ }
95+ };
96+
8597// Dynamic to static dispatch visitor pattern.
86- template <typename Visitor>
87- auto VisitFlatbufferField (const reflection::Schema* absl_nonnull schema,
98+ template <typename Visitor, bool in_container = false >
99+ void VisitFlatbufferField (const reflection::Schema* absl_nonnull schema,
88100 const reflection::Field* absl_nonnull field,
89- Visitor visitor) {
90- auto field_index = field->type ()->index ();
91- switch (field->type ()->base_type ()) {
101+ Visitor&& visitor) {
102+ const auto type =
103+ in_container ? field->type ()->element () : field->type ()->base_type ();
104+ const auto field_index = field->type ()->index ();
105+ const bool is_enum = flatbuffers::IsInteger (type) && field_index >= 0 ;
106+ switch (type) {
92107 case reflection::BaseType::Bool:
93108 visitor.template Visit <bool >(field);
94109 break ;
95110 case reflection::BaseType::Byte:
96- if (field_index >= 0 ) {
111+ if (is_enum ) {
97112 visitor.template Visit <FlatbuffersEnumTag<int8_t >>(field);
98113 } else {
99114 visitor.template Visit <int8_t >(field);
100115 }
101116 break ;
102117 case reflection::BaseType::Short:
103- if (field_index >= 0 ) {
118+ if (is_enum ) {
104119 visitor.template Visit <FlatbuffersEnumTag<int16_t >>(field);
105120 } else {
106121 visitor.template Visit <int16_t >(field);
107122 }
108123 break ;
109124 case reflection::BaseType::Int:
110- if (field_index >= 0 ) {
125+ if (is_enum ) {
111126 visitor.template Visit <FlatbuffersEnumTag<int32_t >>(field);
112127 } else {
113128 visitor.template Visit <int32_t >(field);
114129 }
115130 break ;
116131 case reflection::BaseType::Long:
117- if (field_index >= 0 ) {
132+ if (is_enum ) {
118133 visitor.template Visit <FlatbuffersEnumTag<int64_t >>(field);
119134 } else {
120135 visitor.template Visit <int64_t >(field);
121136 }
122137 break ;
123138 case reflection::BaseType::UByte:
124- if (field_index >= 0 ) {
139+ if (is_enum ) {
125140 visitor.template Visit <FlatbuffersEnumTag<uint8_t >>(field);
126141 } else {
127142 visitor.template Visit <uint8_t >(field);
128143 }
129144 break ;
130145 case reflection::BaseType::UShort:
131- if (field_index >= 0 ) {
146+ if (is_enum ) {
132147 visitor.template Visit <FlatbuffersEnumTag<uint16_t >>(field);
133148 } else {
134149 visitor.template Visit <uint16_t >(field);
135150 }
136151 break ;
137152 case reflection::BaseType::UInt:
138- if (field_index >= 0 ) {
153+ if (is_enum ) {
139154 visitor.template Visit <FlatbuffersEnumTag<uint32_t >>(field);
140155 } else {
141156 visitor.template Visit <uint32_t >(field);
142157 }
143158 break ;
144159 case reflection::BaseType::ULong:
145- if (field_index >= 0 ) {
160+ if (is_enum ) {
146161 visitor.template Visit <FlatbuffersEnumTag<uint64_t >>(field);
147162 } else {
148163 visitor.template Visit <uint64_t >(field);
@@ -159,29 +174,36 @@ auto VisitFlatbufferField(const reflection::Schema* absl_nonnull schema,
159174 break ;
160175 case reflection::BaseType::Vector:
161176 case reflection::BaseType::Vector64:
162- visitor.template Visit <FlatbuffersVectorTag>(field);
177+ if constexpr (in_container) {
178+ FUZZTEST_LOG (FATAL ) << " Nested containers are not supported." ;
179+ } else {
180+ visitor.template Visit <FlatbuffersVectorTag>(field);
181+ }
163182 break ;
164183 case reflection::BaseType::Array:
165- visitor.template Visit <FlatbuffersArrayTag>(field);
184+ if constexpr (in_container) {
185+ FUZZTEST_LOG (FATAL ) << " Nested containers are not supported." ;
186+ } else {
187+ visitor.template Visit <FlatbuffersArrayTag>(field);
188+ }
166189 break ;
167- case reflection::BaseType::Obj: {
168- auto sub_object = schema->objects ()->Get (field->type ()->index ());
169- if (sub_object->is_struct ()) {
190+ case reflection::BaseType::Obj:
191+ if (schema->objects ()->Get (field_index)->is_struct ()) {
170192 visitor.template Visit <FlatbuffersStructTag>(field);
171193 } else {
172194 visitor.template Visit <FlatbuffersTableTag>(field);
173195 }
174196 break ;
175- }
176197 case reflection::BaseType::Union:
177198 visitor.template Visit <FlatbuffersUnionTag>(field);
178199 break ;
179200 case reflection::BaseType::UType:
180- // Noop
201+ // Noop: Union type fields are handled when processing their
202+ // corresponding union field
181203 break ;
182204 default :
183205 FUZZTEST_LOG (FATAL ) << " Unsupported base type: "
184- << field-> type ()-> base_type ( );
206+ << reflection::EnumNameBaseType (type );
185207 }
186208}
187209
@@ -365,7 +387,7 @@ class FlatbuffersTableUntypedDomainImpl
365387 bool IsSupportedField (const reflection::Field* absl_nonnull field) const ;
366388
367389 uint32_t BuildTable (const corpus_type& value,
368- flatbuffers::FlatBufferBuilder & builder) const ;
390+ flatbuffers::FlatBufferBuilder64 & builder) const ;
369391
370392 // Returns the domain for the given field.
371393 // The domain is cached, and the same instance is returned for the same field.
@@ -441,9 +463,15 @@ class FlatbuffersTableUntypedDomainImpl
441463 }
442464 } else if constexpr (std::is_same_v<T, std::string>) {
443465 if (user_value->CheckField (field->offset ())) {
444- inner_value = std::optional (
445- user_value->GetPointer <flatbuffers::String*>(field->offset ())
446- ->str ());
466+ if (field->offset64 ()) {
467+ inner_value = std::optional (
468+ user_value->GetPointer64 <flatbuffers::String*>(field->offset ())
469+ ->str ());
470+ } else {
471+ inner_value = std::optional (
472+ user_value->GetPointer <flatbuffers::String*>(field->offset ())
473+ ->str ());
474+ }
447475 }
448476 } else if constexpr (std::is_same_v<T, FlatbuffersTableTag>) {
449477 auto sub_object = self.schema_ ->objects ()->Get (field->type ()->index ());
@@ -464,9 +492,9 @@ class FlatbuffersTableUntypedDomainImpl
464492 // Create out-of-line table fields, see `BuildTable` for details.
465493 struct TableFieldBuilderVisitor {
466494 const FlatbuffersTableUntypedDomainImpl& self;
467- flatbuffers::FlatBufferBuilder & builder;
468- absl::flat_hash_map<typename corpus_type::key_type, flatbuffers:: uoffset_t >&
469- offsets;
495+ flatbuffers::FlatBufferBuilder64 & builder;
496+ absl::flat_hash_map<typename corpus_type::key_type,
497+ flatbuffers:: uoffset64_t >& offsets;
470498 const typename corpus_type::mapped_type& corpus_value;
471499
472500 template <typename T>
@@ -475,8 +503,16 @@ class FlatbuffersTableUntypedDomainImpl
475503 auto & domain = self.GetCachedDomain <T>(field);
476504 auto user_value = domain.GetValue (corpus_value);
477505 if (user_value.has_value ()) {
478- auto offset =
479- builder.CreateString (user_value->data (), user_value->size ()).o ;
506+ flatbuffers::uoffset64_t offset;
507+ if (field->offset64 ()) {
508+ offset = builder
509+ .CreateString <flatbuffers::Offset64>(
510+ user_value->data (), user_value->size ())
511+ .o ;
512+ } else {
513+ offset =
514+ builder.CreateString (user_value->data (), user_value->size ()).o ;
515+ }
480516 offsets.insert ({field->id (), offset});
481517 }
482518 } else if constexpr (std::is_same_v<T, FlatbuffersTableTag>) {
@@ -502,9 +538,9 @@ class FlatbuffersTableUntypedDomainImpl
502538 // offsets for "out-of-line fields". See `BuildTable` for details.
503539 struct TableBuilderVisitor {
504540 const FlatbuffersTableUntypedDomainImpl& self;
505- flatbuffers::FlatBufferBuilder & builder;
506- const absl::flat_hash_map<typename corpus_type::key_type,
507- flatbuffers::uoffset_t >& offsets;
541+ flatbuffers::FlatBufferBuilder64 & builder;
542+ absl::flat_hash_map<typename corpus_type::key_type,
543+ flatbuffers::uoffset64_t >& offsets;
508544 const typename corpus_type::value_type::second_type& corpus_value;
509545
510546 template <typename T>
@@ -521,9 +557,15 @@ class FlatbuffersTableUntypedDomainImpl
521557 } else if constexpr (std::is_same_v<T, std::string>) {
522558 // "Out-of-line field". Store just offset.
523559 if (auto it = offsets.find (field->id ()); it != offsets.end ()) {
524- builder.AddOffset (
525- field->offset (),
526- flatbuffers::Offset<flatbuffers::String>(it->second ));
560+ if (field->offset64 ()) {
561+ builder.AddOffset (
562+ field->offset (),
563+ flatbuffers::Offset64<flatbuffers::String>(it->second ));
564+ } else {
565+ builder.AddOffset (
566+ field->offset (),
567+ flatbuffers::Offset<flatbuffers::String>(it->second ));
568+ }
527569 }
528570 } else if constexpr (std::is_same_v<T, FlatbuffersTableTag>) {
529571 // "Out-of-line field". Store just offset.
@@ -753,7 +795,7 @@ class FlatbuffersTableDomainImpl
753795
754796 // Converts corpus value into the exact flatbuffer.
755797 value_type GetValue (const corpus_type& value) const {
756- flatbuffers::FlatBufferBuilder builder;
798+ flatbuffers::FlatBufferBuilder64 builder;
757799 const uint32_t offset = inner_->BuildTable (value.untyped_corpus , builder);
758800 builder.Finish (flatbuffers::Offset<flatbuffers::Table>(offset));
759801 value.buffer =
0 commit comments