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_