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