github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/_include/flatbuffers/reflection.h (about) 1 /* 2 * Copyright 2015 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FLATBUFFERS_REFLECTION_H_ 18 #define FLATBUFFERS_REFLECTION_H_ 19 20 // This is somewhat of a circular dependency because flatc (and thus this 21 // file) is needed to generate this header in the first place. 22 // Should normally not be a problem since it can be generated by the 23 // previous version of flatc whenever this code needs to change. 24 // See scripts/generate_code.py for generation. 25 #include "flatbuffers/reflection_generated.h" 26 27 // Helper functionality for reflection. 28 29 namespace flatbuffers { 30 31 // ------------------------- GETTERS ------------------------- 32 33 inline bool IsScalar(reflection::BaseType t) { 34 return t >= reflection::UType && t <= reflection::Double; 35 } 36 inline bool IsInteger(reflection::BaseType t) { 37 return t >= reflection::UType && t <= reflection::ULong; 38 } 39 inline bool IsFloat(reflection::BaseType t) { 40 return t == reflection::Float || t == reflection::Double; 41 } 42 inline bool IsLong(reflection::BaseType t) { 43 return t == reflection::Long || t == reflection::ULong; 44 } 45 46 // Size of a basic type, don't use with structs. 47 inline size_t GetTypeSize(reflection::BaseType base_type) { 48 // This needs to correspond to the BaseType enum. 49 static size_t sizes[] = { 50 0, // None 51 1, // UType 52 1, // Bool 53 1, // Byte 54 1, // UByte 55 2, // Short 56 2, // UShort 57 4, // Int 58 4, // UInt 59 8, // Long 60 8, // ULong 61 4, // Float 62 8, // Double 63 4, // String 64 4, // Vector 65 4, // Obj 66 4, // Union 67 0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds 68 // errors. 69 8, // Vector64 70 71 0 // MaxBaseType. This must be kept the last entry in this array. 72 }; 73 static_assert(sizeof(sizes) / sizeof(size_t) == reflection::MaxBaseType + 1, 74 "Size of sizes[] array does not match the count of BaseType " 75 "enum values."); 76 return sizes[base_type]; 77 } 78 79 // Same as above, but now correctly returns the size of a struct if 80 // the field (or vector element) is a struct. 81 inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index, 82 const reflection::Schema &schema) { 83 if (base_type == reflection::Obj && 84 schema.objects()->Get(type_index)->is_struct()) { 85 return schema.objects()->Get(type_index)->bytesize(); 86 } else { 87 return GetTypeSize(base_type); 88 } 89 } 90 91 // Get the root, regardless of what type it is. 92 inline Table *GetAnyRoot(uint8_t *const flatbuf) { 93 return GetMutableRoot<Table>(flatbuf); 94 } 95 96 inline const Table *GetAnyRoot(const uint8_t *const flatbuf) { 97 return GetRoot<Table>(flatbuf); 98 } 99 100 inline Table *GetAnySizePrefixedRoot(uint8_t *const flatbuf) { 101 return GetMutableSizePrefixedRoot<Table>(flatbuf); 102 } 103 104 inline const Table *GetAnySizePrefixedRoot(const uint8_t *const flatbuf) { 105 return GetSizePrefixedRoot<Table>(flatbuf); 106 } 107 108 // Get a field's default, if you know it's an integer, and its exact type. 109 template<typename T> T GetFieldDefaultI(const reflection::Field &field) { 110 FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); 111 return static_cast<T>(field.default_integer()); 112 } 113 114 // Get a field's default, if you know it's floating point and its exact type. 115 template<typename T> T GetFieldDefaultF(const reflection::Field &field) { 116 FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); 117 return static_cast<T>(field.default_real()); 118 } 119 120 // Get a field, if you know it's an integer, and its exact type. 121 template<typename T> 122 T GetFieldI(const Table &table, const reflection::Field &field) { 123 FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); 124 return table.GetField<T>(field.offset(), 125 static_cast<T>(field.default_integer())); 126 } 127 128 // Get a field, if you know it's floating point and its exact type. 129 template<typename T> 130 T GetFieldF(const Table &table, const reflection::Field &field) { 131 FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); 132 return table.GetField<T>(field.offset(), 133 static_cast<T>(field.default_real())); 134 } 135 136 // Get a field, if you know it's a string. 137 inline const String *GetFieldS(const Table &table, 138 const reflection::Field &field) { 139 FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String); 140 return table.GetPointer<const String *>(field.offset()); 141 } 142 143 // Get a field, if you know it's a vector. 144 template<typename T> 145 Vector<T> *GetFieldV(const Table &table, const reflection::Field &field) { 146 FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector && 147 sizeof(T) == GetTypeSize(field.type()->element())); 148 return table.GetPointer<Vector<T> *>(field.offset()); 149 } 150 151 // Get a field, if you know it's a vector, generically. 152 // To actually access elements, use the return value together with 153 // field.type()->element() in any of GetAnyVectorElemI below etc. 154 inline VectorOfAny *GetFieldAnyV(const Table &table, 155 const reflection::Field &field) { 156 return table.GetPointer<VectorOfAny *>(field.offset()); 157 } 158 159 // Get a field, if you know it's a table. 160 inline Table *GetFieldT(const Table &table, const reflection::Field &field) { 161 FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj || 162 field.type()->base_type() == reflection::Union); 163 return table.GetPointer<Table *>(field.offset()); 164 } 165 166 // Get a field, if you know it's a struct. 167 inline const Struct *GetFieldStruct(const Table &table, 168 const reflection::Field &field) { 169 // TODO: This does NOT check if the field is a table or struct, but we'd need 170 // access to the schema to check the is_struct flag. 171 FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj); 172 return table.GetStruct<const Struct *>(field.offset()); 173 } 174 175 // Get a structure's field, if you know it's a struct. 176 inline const Struct *GetFieldStruct(const Struct &structure, 177 const reflection::Field &field) { 178 FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj); 179 return structure.GetStruct<const Struct *>(field.offset()); 180 } 181 182 // Raw helper functions used below: get any value in memory as a 64bit int, a 183 // double or a string. 184 // All scalars get static_cast to an int64_t, strings use strtoull, every other 185 // data type returns 0. 186 int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data); 187 // All scalars static cast to double, strings use strtod, every other data 188 // type is 0.0. 189 double GetAnyValueF(reflection::BaseType type, const uint8_t *data); 190 // All scalars converted using stringstream, strings as-is, and all other 191 // data types provide some level of debug-pretty-printing. 192 std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data, 193 const reflection::Schema *schema, int type_index); 194 195 // Get any table field as a 64bit int, regardless of what type it is. 196 inline int64_t GetAnyFieldI(const Table &table, 197 const reflection::Field &field) { 198 auto field_ptr = table.GetAddressOf(field.offset()); 199 return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr) 200 : field.default_integer(); 201 } 202 203 // Get any table field as a double, regardless of what type it is. 204 inline double GetAnyFieldF(const Table &table, const reflection::Field &field) { 205 auto field_ptr = table.GetAddressOf(field.offset()); 206 return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr) 207 : field.default_real(); 208 } 209 210 // Get any table field as a string, regardless of what type it is. 211 // You may pass nullptr for the schema if you don't care to have fields that 212 // are of table type pretty-printed. 213 inline std::string GetAnyFieldS(const Table &table, 214 const reflection::Field &field, 215 const reflection::Schema *schema) { 216 auto field_ptr = table.GetAddressOf(field.offset()); 217 return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema, 218 field.type()->index()) 219 : ""; 220 } 221 222 // Get any struct field as a 64bit int, regardless of what type it is. 223 inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) { 224 return GetAnyValueI(field.type()->base_type(), 225 st.GetAddressOf(field.offset())); 226 } 227 228 // Get any struct field as a double, regardless of what type it is. 229 inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) { 230 return GetAnyValueF(field.type()->base_type(), 231 st.GetAddressOf(field.offset())); 232 } 233 234 // Get any struct field as a string, regardless of what type it is. 235 inline std::string GetAnyFieldS(const Struct &st, 236 const reflection::Field &field) { 237 return GetAnyValueS(field.type()->base_type(), 238 st.GetAddressOf(field.offset()), nullptr, -1); 239 } 240 241 // Get any vector element as a 64bit int, regardless of what type it is. 242 inline int64_t GetAnyVectorElemI(const VectorOfAny *vec, 243 reflection::BaseType elem_type, size_t i) { 244 return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i); 245 } 246 247 // Get any vector element as a double, regardless of what type it is. 248 inline double GetAnyVectorElemF(const VectorOfAny *vec, 249 reflection::BaseType elem_type, size_t i) { 250 return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i); 251 } 252 253 // Get any vector element as a string, regardless of what type it is. 254 inline std::string GetAnyVectorElemS(const VectorOfAny *vec, 255 reflection::BaseType elem_type, size_t i) { 256 return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, 257 nullptr, -1); 258 } 259 260 // Get a vector element that's a table/string/vector from a generic vector. 261 // Pass Table/String/VectorOfAny as template parameter. 262 // Warning: does no typechecking. 263 template<typename T> 264 T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) { 265 auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i; 266 return reinterpret_cast<T *>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr)); 267 } 268 269 // Get the inline-address of a vector element. Useful for Structs (pass Struct 270 // as template arg), or being able to address a range of scalars in-line. 271 // Get elem_size from GetTypeSizeInline(). 272 // Note: little-endian data on all platforms, use EndianScalar() instead of 273 // raw pointer access with scalars). 274 template<typename T> 275 T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i, 276 size_t elem_size) { 277 return reinterpret_cast<T *>(vec->Data() + elem_size * i); 278 } 279 280 // Similarly, for elements of tables. 281 template<typename T> 282 T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) { 283 return reinterpret_cast<T *>(table.GetAddressOf(field.offset())); 284 } 285 286 // Similarly, for elements of structs. 287 template<typename T> 288 T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) { 289 return reinterpret_cast<T *>(st.GetAddressOf(field.offset())); 290 } 291 292 // Loop over all the fields of the provided `object` and call `func` on each one 293 // in increasing order by their field->id(). If `reverse` is true, `func` is 294 // called in descending order 295 void ForAllFields(const reflection::Object *object, bool reverse, 296 std::function<void(const reflection::Field *)> func); 297 298 // ------------------------- SETTERS ------------------------- 299 300 // Set any scalar field, if you know its exact type. 301 template<typename T> 302 bool SetField(Table *table, const reflection::Field &field, T val) { 303 reflection::BaseType type = field.type()->base_type(); 304 if (!IsScalar(type)) { return false; } 305 FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type)); 306 T def; 307 if (IsInteger(type)) { 308 def = GetFieldDefaultI<T>(field); 309 } else { 310 FLATBUFFERS_ASSERT(IsFloat(type)); 311 def = GetFieldDefaultF<T>(field); 312 } 313 return table->SetField(field.offset(), val, def); 314 } 315 316 // Raw helper functions used below: set any value in memory as a 64bit int, a 317 // double or a string. 318 // These work for all scalar values, but do nothing for other data types. 319 // To set a string, see SetString below. 320 void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val); 321 void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val); 322 void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val); 323 324 // Set any table field as a 64bit int, regardless of type what it is. 325 inline bool SetAnyFieldI(Table *table, const reflection::Field &field, 326 int64_t val) { 327 auto field_ptr = table->GetAddressOf(field.offset()); 328 if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field); 329 SetAnyValueI(field.type()->base_type(), field_ptr, val); 330 return true; 331 } 332 333 // Set any table field as a double, regardless of what type it is. 334 inline bool SetAnyFieldF(Table *table, const reflection::Field &field, 335 double val) { 336 auto field_ptr = table->GetAddressOf(field.offset()); 337 if (!field_ptr) return val == GetFieldDefaultF<double>(field); 338 SetAnyValueF(field.type()->base_type(), field_ptr, val); 339 return true; 340 } 341 342 // Set any table field as a string, regardless of what type it is. 343 inline bool SetAnyFieldS(Table *table, const reflection::Field &field, 344 const char *val) { 345 auto field_ptr = table->GetAddressOf(field.offset()); 346 if (!field_ptr) return false; 347 SetAnyValueS(field.type()->base_type(), field_ptr, val); 348 return true; 349 } 350 351 // Set any struct field as a 64bit int, regardless of type what it is. 352 inline void SetAnyFieldI(Struct *st, const reflection::Field &field, 353 int64_t val) { 354 SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()), 355 val); 356 } 357 358 // Set any struct field as a double, regardless of type what it is. 359 inline void SetAnyFieldF(Struct *st, const reflection::Field &field, 360 double val) { 361 SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()), 362 val); 363 } 364 365 // Set any struct field as a string, regardless of type what it is. 366 inline void SetAnyFieldS(Struct *st, const reflection::Field &field, 367 const char *val) { 368 SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()), 369 val); 370 } 371 372 // Set any vector element as a 64bit int, regardless of type what it is. 373 inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type, 374 size_t i, int64_t val) { 375 SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); 376 } 377 378 // Set any vector element as a double, regardless of type what it is. 379 inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type, 380 size_t i, double val) { 381 SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); 382 } 383 384 // Set any vector element as a string, regardless of type what it is. 385 inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type, 386 size_t i, const char *val) { 387 SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); 388 } 389 390 // ------------------------- RESIZING SETTERS ------------------------- 391 392 // "smart" pointer for use with resizing vectors: turns a pointer inside 393 // a vector into a relative offset, such that it is not affected by resizes. 394 template<typename T, typename U> class pointer_inside_vector { 395 public: 396 pointer_inside_vector(T *ptr, std::vector<U> &vec) 397 : offset_(reinterpret_cast<uint8_t *>(ptr) - 398 reinterpret_cast<uint8_t *>(vec.data())), 399 vec_(vec) {} 400 401 T *operator*() const { 402 return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(vec_.data()) + 403 offset_); 404 } 405 T *operator->() const { return operator*(); } 406 407 private: 408 size_t offset_; 409 std::vector<U> &vec_; 410 }; 411 412 // Helper to create the above easily without specifying template args. 413 template<typename T, typename U> 414 pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) { 415 return pointer_inside_vector<T, U>(ptr, vec); 416 } 417 418 inline const char *UnionTypeFieldSuffix() { return "_type"; } 419 420 // Helper to figure out the actual table type a union refers to. 421 inline const reflection::Object &GetUnionType( 422 const reflection::Schema &schema, const reflection::Object &parent, 423 const reflection::Field &unionfield, const Table &table) { 424 auto enumdef = schema.enums()->Get(unionfield.type()->index()); 425 // TODO: this is clumsy and slow, but no other way to find it? 426 auto type_field = parent.fields()->LookupByKey( 427 (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str()); 428 FLATBUFFERS_ASSERT(type_field); 429 auto union_type = GetFieldI<uint8_t>(table, *type_field); 430 auto enumval = enumdef->values()->LookupByKey(union_type); 431 return *schema.objects()->Get(enumval->union_type()->index()); 432 } 433 434 // Changes the contents of a string inside a FlatBuffer. FlatBuffer must 435 // live inside a std::vector so we can resize the buffer if needed. 436 // "str" must live inside "flatbuf" and may be invalidated after this call. 437 // If your FlatBuffer's root table is not the schema's root table, you should 438 // pass in your root_table type as well. 439 void SetString(const reflection::Schema &schema, const std::string &val, 440 const String *str, std::vector<uint8_t> *flatbuf, 441 const reflection::Object *root_table = nullptr); 442 443 // Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must 444 // live inside a std::vector so we can resize the buffer if needed. 445 // "vec" must live inside "flatbuf" and may be invalidated after this call. 446 // If your FlatBuffer's root table is not the schema's root table, you should 447 // pass in your root_table type as well. 448 uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, 449 const VectorOfAny *vec, uoffset_t num_elems, 450 uoffset_t elem_size, std::vector<uint8_t> *flatbuf, 451 const reflection::Object *root_table = nullptr); 452 453 template<typename T> 454 void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val, 455 const Vector<T> *vec, std::vector<uint8_t> *flatbuf, 456 const reflection::Object *root_table = nullptr) { 457 auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size()); 458 auto newelems = ResizeAnyVector( 459 schema, newsize, reinterpret_cast<const VectorOfAny *>(vec), vec->size(), 460 static_cast<uoffset_t>(sizeof(T)), flatbuf, root_table); 461 // Set new elements to "val". 462 for (int i = 0; i < delta_elem; i++) { 463 auto loc = newelems + i * sizeof(T); 464 auto is_scalar = flatbuffers::is_scalar<T>::value; 465 if (is_scalar) { 466 WriteScalar(loc, val); 467 } else { // struct 468 *reinterpret_cast<T *>(loc) = val; 469 } 470 } 471 } 472 473 // Adds any new data (in the form of a new FlatBuffer) to an existing 474 // FlatBuffer. This can be used when any of the above methods are not 475 // sufficient, in particular for adding new tables and new fields. 476 // This is potentially slightly less efficient than a FlatBuffer constructed 477 // in one piece, since the new FlatBuffer doesn't share any vtables with the 478 // existing one. 479 // The return value can now be set using Vector::MutateOffset or SetFieldT 480 // below. 481 const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf, 482 const uint8_t *newbuf, size_t newlen); 483 484 inline bool SetFieldT(Table *table, const reflection::Field &field, 485 const uint8_t *val) { 486 FLATBUFFERS_ASSERT(sizeof(uoffset_t) == 487 GetTypeSize(field.type()->base_type())); 488 return table->SetPointer(field.offset(), val); 489 } 490 491 // ------------------------- COPYING ------------------------- 492 493 // Generic copying of tables from a FlatBuffer into a FlatBuffer builder. 494 // Can be used to do any kind of merging/selecting you may want to do out 495 // of existing buffers. Also useful to reconstruct a whole buffer if the 496 // above resizing functionality has introduced garbage in a buffer you want 497 // to remove. 498 // Note: this does not deal with DAGs correctly. If the table passed forms a 499 // DAG, the copy will be a tree instead (with duplicates). Strings can be 500 // shared however, by passing true for use_string_pooling. 501 502 Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, 503 const reflection::Schema &schema, 504 const reflection::Object &objectdef, 505 const Table &table, 506 bool use_string_pooling = false); 507 508 // Verifies the provided flatbuffer using reflection. 509 // root should point to the root type for this flatbuffer. 510 // buf should point to the start of flatbuffer data. 511 // length specifies the size of the flatbuffer data. 512 bool Verify(const reflection::Schema &schema, const reflection::Object &root, 513 const uint8_t *buf, size_t length, uoffset_t max_depth = 64, 514 uoffset_t max_tables = 1000000); 515 516 bool VerifySizePrefixed(const reflection::Schema &schema, 517 const reflection::Object &root, const uint8_t *buf, 518 size_t length, uoffset_t max_depth = 64, 519 uoffset_t max_tables = 1000000); 520 521 } // namespace flatbuffers 522 523 #endif // FLATBUFFERS_REFLECTION_H_