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_