github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/_include/flatbuffers/buffer.h (about)

     1  /*
     2   * Copyright 2021 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_BUFFER_H_
    18  #define FLATBUFFERS_BUFFER_H_
    19  
    20  #include <algorithm>
    21  
    22  #include "flatbuffers/base.h"
    23  
    24  namespace flatbuffers {
    25  
    26  // Wrapper for uoffset_t to allow safe template specialization.
    27  // Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
    28  template<typename T = void> struct Offset {
    29    // The type of offset to use.
    30    typedef uoffset_t offset_type;
    31  
    32    offset_type o;
    33    Offset() : o(0) {}
    34    Offset(const offset_type _o) : o(_o) {}
    35    Offset<> Union() const { return o; }
    36    bool IsNull() const { return !o; }
    37  };
    38  
    39  // Wrapper for uoffset64_t Offsets.
    40  template<typename T = void> struct Offset64 {
    41    // The type of offset to use.
    42    typedef uoffset64_t offset_type;
    43  
    44    offset_type o;
    45    Offset64() : o(0) {}
    46    Offset64(const offset_type offset) : o(offset) {}
    47    Offset64<> Union() const { return o; }
    48    bool IsNull() const { return !o; }
    49  };
    50  
    51  // Litmus check for ensuring the Offsets are the expected size.
    52  static_assert(sizeof(Offset<>) == 4, "Offset has wrong size");
    53  static_assert(sizeof(Offset64<>) == 8, "Offset64 has wrong size");
    54  
    55  inline void EndianCheck() {
    56    int endiantest = 1;
    57    // If this fails, see FLATBUFFERS_LITTLEENDIAN above.
    58    FLATBUFFERS_ASSERT(*reinterpret_cast<char *>(&endiantest) ==
    59                       FLATBUFFERS_LITTLEENDIAN);
    60    (void)endiantest;
    61  }
    62  
    63  template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() {
    64    // clang-format off
    65    #ifdef _MSC_VER
    66      return __alignof(T);
    67    #else
    68      #ifndef alignof
    69        return __alignof__(T);
    70      #else
    71        return alignof(T);
    72      #endif
    73    #endif
    74    // clang-format on
    75  }
    76  
    77  // Lexicographically compare two strings (possibly containing nulls), and
    78  // return true if the first is less than the second.
    79  static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
    80                                    const char *b_data, uoffset_t b_size) {
    81    const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size));
    82    return cmp == 0 ? a_size < b_size : cmp < 0;
    83  }
    84  
    85  // When we read serialized data from memory, in the case of most scalars,
    86  // we want to just read T, but in the case of Offset, we want to actually
    87  // perform the indirection and return a pointer.
    88  // The template specialization below does just that.
    89  // It is wrapped in a struct since function templates can't overload on the
    90  // return type like this.
    91  // The typedef is for the convenience of callers of this function
    92  // (avoiding the need for a trailing return decltype)
    93  template<typename T> struct IndirectHelper {
    94    typedef T return_type;
    95    typedef T mutable_return_type;
    96    static const size_t element_stride = sizeof(T);
    97  
    98    static return_type Read(const uint8_t *p, const size_t i) {
    99      return EndianScalar((reinterpret_cast<const T *>(p))[i]);
   100    }
   101    static mutable_return_type Read(uint8_t *p, const size_t i) {
   102      return reinterpret_cast<mutable_return_type>(
   103          Read(const_cast<const uint8_t *>(p), i));
   104    }
   105  };
   106  
   107  // For vector of Offsets.
   108  template<typename T, template<typename> class OffsetT>
   109  struct IndirectHelper<OffsetT<T>> {
   110    typedef const T *return_type;
   111    typedef T *mutable_return_type;
   112    typedef typename OffsetT<T>::offset_type offset_type;
   113    static const offset_type element_stride = sizeof(offset_type);
   114  
   115    static return_type Read(const uint8_t *const p, const offset_type i) {
   116      // Offsets are relative to themselves, so first update the pointer to
   117      // point to the offset location.
   118      const uint8_t *const offset_location = p + i * element_stride;
   119  
   120      // Then read the scalar value of the offset (which may be 32 or 64-bits) and
   121      // then determine the relative location from the offset location.
   122      return reinterpret_cast<return_type>(
   123          offset_location + ReadScalar<offset_type>(offset_location));
   124    }
   125    static mutable_return_type Read(uint8_t *const p, const offset_type i) {
   126      // Offsets are relative to themselves, so first update the pointer to
   127      // point to the offset location.
   128      uint8_t *const offset_location = p + i * element_stride;
   129  
   130      // Then read the scalar value of the offset (which may be 32 or 64-bits) and
   131      // then determine the relative location from the offset location.
   132      return reinterpret_cast<mutable_return_type>(
   133          offset_location + ReadScalar<offset_type>(offset_location));
   134    }
   135  };
   136  
   137  // For vector of structs.
   138  template<typename T> struct IndirectHelper<const T *> {
   139    typedef const T *return_type;
   140    typedef T *mutable_return_type;
   141    static const size_t element_stride = sizeof(T);
   142  
   143    static return_type Read(const uint8_t *const p, const size_t i) {
   144      // Structs are stored inline, relative to the first struct pointer.
   145      return reinterpret_cast<return_type>(p + i * element_stride);
   146    }
   147    static mutable_return_type Read(uint8_t *const p, const size_t i) {
   148      // Structs are stored inline, relative to the first struct pointer.
   149      return reinterpret_cast<mutable_return_type>(p + i * element_stride);
   150    }
   151  };
   152  
   153  /// @brief Get a pointer to the file_identifier section of the buffer.
   154  /// @return Returns a const char pointer to the start of the file_identifier
   155  /// characters in the buffer.  The returned char * has length
   156  /// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'.
   157  /// This function is UNDEFINED for FlatBuffers whose schema does not include
   158  /// a file_identifier (likely points at padding or the start of a the root
   159  /// vtable).
   160  inline const char *GetBufferIdentifier(const void *buf,
   161                                         bool size_prefixed = false) {
   162    return reinterpret_cast<const char *>(buf) +
   163           ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t));
   164  }
   165  
   166  // Helper to see if the identifier in a buffer has the expected value.
   167  inline bool BufferHasIdentifier(const void *buf, const char *identifier,
   168                                  bool size_prefixed = false) {
   169    return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier,
   170                   flatbuffers::kFileIdentifierLength) == 0;
   171  }
   172  
   173  /// @cond FLATBUFFERS_INTERNAL
   174  // Helpers to get a typed pointer to the root object contained in the buffer.
   175  template<typename T> T *GetMutableRoot(void *buf) {
   176    if (!buf) return nullptr;
   177    EndianCheck();
   178    return reinterpret_cast<T *>(
   179        reinterpret_cast<uint8_t *>(buf) +
   180        EndianScalar(*reinterpret_cast<uoffset_t *>(buf)));
   181  }
   182  
   183  template<typename T, typename SizeT = uoffset_t>
   184  T *GetMutableSizePrefixedRoot(void *buf) {
   185    return GetMutableRoot<T>(reinterpret_cast<uint8_t *>(buf) + sizeof(SizeT));
   186  }
   187  
   188  template<typename T> const T *GetRoot(const void *buf) {
   189    return GetMutableRoot<T>(const_cast<void *>(buf));
   190  }
   191  
   192  template<typename T, typename SizeT = uoffset_t>
   193  const T *GetSizePrefixedRoot(const void *buf) {
   194    return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(SizeT));
   195  }
   196  
   197  }  // namespace flatbuffers
   198  
   199  #endif  // FLATBUFFERS_BUFFER_H_