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_