1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_BUFFER_ITERATOR_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_BUFFER_ITERATOR_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <string.h> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Worker #include <concepts> 11*6777b538SAndroid Build Coastguard Worker #include <optional> 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h" 14*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h" 15*6777b538SAndroid Build Coastguard Worker #include "base/numerics/checked_math.h" 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker namespace base { 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker // BufferIterator is a bounds-checked container utility to access variable- 20*6777b538SAndroid Build Coastguard Worker // length, heterogeneous structures contained within a buffer. If the data are 21*6777b538SAndroid Build Coastguard Worker // homogeneous, use base::span<> instead. 22*6777b538SAndroid Build Coastguard Worker // 23*6777b538SAndroid Build Coastguard Worker // After being created with a weakly-owned buffer, BufferIterator returns 24*6777b538SAndroid Build Coastguard Worker // pointers to structured data within the buffer. After each method call that 25*6777b538SAndroid Build Coastguard Worker // returns data in the buffer, the iterator position is advanced by the byte 26*6777b538SAndroid Build Coastguard Worker // size of the object (or span of objects) returned. If there are not enough 27*6777b538SAndroid Build Coastguard Worker // bytes remaining in the buffer to return the requested object(s), a nullptr 28*6777b538SAndroid Build Coastguard Worker // or empty span is returned. 29*6777b538SAndroid Build Coastguard Worker // 30*6777b538SAndroid Build Coastguard Worker // This class is similar to base::Pickle, which should be preferred for 31*6777b538SAndroid Build Coastguard Worker // serializing to disk. Pickle versions its header and does not support writing 32*6777b538SAndroid Build Coastguard Worker // structures, which are problematic for serialization due to struct padding and 33*6777b538SAndroid Build Coastguard Worker // version shear concerns. 34*6777b538SAndroid Build Coastguard Worker // 35*6777b538SAndroid Build Coastguard Worker // Example usage: 36*6777b538SAndroid Build Coastguard Worker // 37*6777b538SAndroid Build Coastguard Worker // std::vector<uint8_t> buffer(4096); 38*6777b538SAndroid Build Coastguard Worker // if (!ReadSomeData(&buffer, buffer.size())) { 39*6777b538SAndroid Build Coastguard Worker // LOG(ERROR) << "Failed to read data."; 40*6777b538SAndroid Build Coastguard Worker // return false; 41*6777b538SAndroid Build Coastguard Worker // } 42*6777b538SAndroid Build Coastguard Worker // 43*6777b538SAndroid Build Coastguard Worker // BufferIterator<uint8_t> iterator(buffer); 44*6777b538SAndroid Build Coastguard Worker // uint32_t* num_items = iterator.Object<uint32_t>(); 45*6777b538SAndroid Build Coastguard Worker // if (!num_items) { 46*6777b538SAndroid Build Coastguard Worker // LOG(ERROR) << "No num_items field." 47*6777b538SAndroid Build Coastguard Worker // return false; 48*6777b538SAndroid Build Coastguard Worker // } 49*6777b538SAndroid Build Coastguard Worker // 50*6777b538SAndroid Build Coastguard Worker // base::span<const item_struct> items = 51*6777b538SAndroid Build Coastguard Worker // iterator.Span<item_struct>(*num_items); 52*6777b538SAndroid Build Coastguard Worker // if (items.size() != *num_items) { 53*6777b538SAndroid Build Coastguard Worker // LOG(ERROR) << "Not enough items."; 54*6777b538SAndroid Build Coastguard Worker // return false; 55*6777b538SAndroid Build Coastguard Worker // } 56*6777b538SAndroid Build Coastguard Worker // 57*6777b538SAndroid Build Coastguard Worker // // ... validate the objects in |items|. 58*6777b538SAndroid Build Coastguard Worker template <typename B> 59*6777b538SAndroid Build Coastguard Worker class BufferIterator { 60*6777b538SAndroid Build Coastguard Worker public: 61*6777b538SAndroid Build Coastguard Worker static_assert(std::same_as<std::remove_const_t<B>, char> || 62*6777b538SAndroid Build Coastguard Worker std::same_as<std::remove_const_t<B>, unsigned char>, 63*6777b538SAndroid Build Coastguard Worker "Underlying buffer type must be char-type."); 64*6777b538SAndroid Build Coastguard Worker // Constructs an empty BufferIterator that will always return null pointers. BufferIterator()65*6777b538SAndroid Build Coastguard Worker BufferIterator() {} 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard Worker // Constructs a BufferIterator over the `buffer` span, that will return 68*6777b538SAndroid Build Coastguard Worker // pointers into the span. BufferIterator(span<B> buffer)69*6777b538SAndroid Build Coastguard Worker explicit BufferIterator(span<B> buffer) 70*6777b538SAndroid Build Coastguard Worker : buffer_(buffer), remaining_(buffer) {} 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/40284755): Move all callers to use spans and remove this. BufferIterator(B * data,size_t size)73*6777b538SAndroid Build Coastguard Worker UNSAFE_BUFFER_USAGE BufferIterator(B* data, size_t size) 74*6777b538SAndroid Build Coastguard Worker : BufferIterator( 75*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/40284755): Remove this constructor entirely, 76*6777b538SAndroid Build Coastguard Worker // callers should provide a span. There's no way to know that the 77*6777b538SAndroid Build Coastguard Worker // size is correct here. 78*6777b538SAndroid Build Coastguard Worker UNSAFE_BUFFERS(span(data, size))) {} 79*6777b538SAndroid Build Coastguard Worker 80*6777b538SAndroid Build Coastguard Worker // Copies out an object. As compared to using `Object`, this avoids potential 81*6777b538SAndroid Build Coastguard Worker // unaligned access which may be undefined behavior. 82*6777b538SAndroid Build Coastguard Worker template <typename T, 83*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> CopyObject()84*6777b538SAndroid Build Coastguard Worker std::optional<T> CopyObject() { 85*6777b538SAndroid Build Coastguard Worker std::optional<T> t; 86*6777b538SAndroid Build Coastguard Worker if (remaining_.size() >= sizeof(T)) { 87*6777b538SAndroid Build Coastguard Worker auto [source, remain] = remaining_.template split_at<sizeof(T)>(); 88*6777b538SAndroid Build Coastguard Worker byte_span_from_ref(t.emplace()).copy_from(as_bytes(source)); 89*6777b538SAndroid Build Coastguard Worker remaining_ = remain; 90*6777b538SAndroid Build Coastguard Worker } 91*6777b538SAndroid Build Coastguard Worker return t; 92*6777b538SAndroid Build Coastguard Worker } 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker // Returns a const pointer to an object of type T in the buffer at the current 95*6777b538SAndroid Build Coastguard Worker // position. 96*6777b538SAndroid Build Coastguard Worker // 97*6777b538SAndroid Build Coastguard Worker // # Safety 98*6777b538SAndroid Build Coastguard Worker // Note that the buffer's current position must be aligned for the type T 99*6777b538SAndroid Build Coastguard Worker // or using the pointer will cause Undefined Behaviour. Generally prefer 100*6777b538SAndroid Build Coastguard Worker // `CopyObject` as it avoids this problem entirely. 101*6777b538SAndroid Build Coastguard Worker // TODO(danakj): We should probably CHECK this instead of allowing UB into 102*6777b538SAndroid Build Coastguard Worker // production. 103*6777b538SAndroid Build Coastguard Worker template <typename T, 104*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> Object()105*6777b538SAndroid Build Coastguard Worker const T* Object() { 106*6777b538SAndroid Build Coastguard Worker return MutableObject<const T>(); 107*6777b538SAndroid Build Coastguard Worker } 108*6777b538SAndroid Build Coastguard Worker 109*6777b538SAndroid Build Coastguard Worker // Returns a pointer to a mutable structure T in the buffer at the current 110*6777b538SAndroid Build Coastguard Worker // position. On success, the iterator position is advanced by sizeof(T). If 111*6777b538SAndroid Build Coastguard Worker // there are not sizeof(T) bytes remaining in the buffer, returns nullptr. 112*6777b538SAndroid Build Coastguard Worker // 113*6777b538SAndroid Build Coastguard Worker // # Safety 114*6777b538SAndroid Build Coastguard Worker // Note that the buffer's current position must be aligned for the type T or 115*6777b538SAndroid Build Coastguard Worker // using the pointer will cause Undefined Behaviour. Generally prefer 116*6777b538SAndroid Build Coastguard Worker // `CopyObject` as it avoids this problem entirely. 117*6777b538SAndroid Build Coastguard Worker // TODO(danakj): We should probably CHECK this instead of allowing UB into 118*6777b538SAndroid Build Coastguard Worker // production. 119*6777b538SAndroid Build Coastguard Worker template <typename T, 120*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> MutableObject()121*6777b538SAndroid Build Coastguard Worker T* MutableObject() { 122*6777b538SAndroid Build Coastguard Worker T* t = nullptr; 123*6777b538SAndroid Build Coastguard Worker if (remaining_.size() >= sizeof(T)) { 124*6777b538SAndroid Build Coastguard Worker auto [source, remain] = remaining_.template split_at<sizeof(T)>(); 125*6777b538SAndroid Build Coastguard Worker // TODO(danakj): This is UB without creating a lifetime for the object in 126*6777b538SAndroid Build Coastguard Worker // the compiler, which we can not do before C++23: 127*6777b538SAndroid Build Coastguard Worker // https://en.cppreference.com/w/cpp/memory/start_lifetime_as 128*6777b538SAndroid Build Coastguard Worker t = reinterpret_cast<T*>(source.data()); 129*6777b538SAndroid Build Coastguard Worker remaining_ = remain; 130*6777b538SAndroid Build Coastguard Worker } 131*6777b538SAndroid Build Coastguard Worker return t; 132*6777b538SAndroid Build Coastguard Worker } 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker // Returns a span of |count| T objects in the buffer at the current position. 135*6777b538SAndroid Build Coastguard Worker // On success, the iterator position is advanced by |sizeof(T) * count|. If 136*6777b538SAndroid Build Coastguard Worker // there are not enough bytes remaining in the buffer to fulfill the request, 137*6777b538SAndroid Build Coastguard Worker // returns an empty span. 138*6777b538SAndroid Build Coastguard Worker // 139*6777b538SAndroid Build Coastguard Worker // # Safety 140*6777b538SAndroid Build Coastguard Worker // Note that the buffer's current position must be aligned for the type T or 141*6777b538SAndroid Build Coastguard Worker // using the span will cause Undefined Behaviour. 142*6777b538SAndroid Build Coastguard Worker // TODO(danakj): We should probably CHECK this instead of allowing UB into 143*6777b538SAndroid Build Coastguard Worker // production. 144*6777b538SAndroid Build Coastguard Worker template <typename T, 145*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> MutableSpan(size_t count)146*6777b538SAndroid Build Coastguard Worker span<T> MutableSpan(size_t count) { 147*6777b538SAndroid Build Coastguard Worker size_t byte_size; 148*6777b538SAndroid Build Coastguard Worker if (!CheckMul(sizeof(T), count).AssignIfValid(&byte_size)) { 149*6777b538SAndroid Build Coastguard Worker return span<T>(); 150*6777b538SAndroid Build Coastguard Worker } 151*6777b538SAndroid Build Coastguard Worker if (byte_size > remaining_.size()) { 152*6777b538SAndroid Build Coastguard Worker return span<T>(); 153*6777b538SAndroid Build Coastguard Worker } 154*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = remaining_.split_at(byte_size); 155*6777b538SAndroid Build Coastguard Worker remaining_ = rhs; 156*6777b538SAndroid Build Coastguard Worker // SAFETY: The byte size of `span<T>` with size `count` is `count * 157*6777b538SAndroid Build Coastguard Worker // sizeof(T)` which is exactly `byte_size`, the byte size of `lhs`. 158*6777b538SAndroid Build Coastguard Worker // 159*6777b538SAndroid Build Coastguard Worker // TODO(danakj): This is UB without creating a lifetime for the object in 160*6777b538SAndroid Build Coastguard Worker // the compiler, which we can not do before C++23: 161*6777b538SAndroid Build Coastguard Worker // https://en.cppreference.com/w/cpp/memory/start_lifetime_as 162*6777b538SAndroid Build Coastguard Worker return UNSAFE_BUFFERS(span<T>(reinterpret_cast<T*>(lhs.data()), count)); 163*6777b538SAndroid Build Coastguard Worker } 164*6777b538SAndroid Build Coastguard Worker 165*6777b538SAndroid Build Coastguard Worker // An overload for when the size is known at compile time. The result will be 166*6777b538SAndroid Build Coastguard Worker // a fixed-size span. 167*6777b538SAndroid Build Coastguard Worker template <typename T, 168*6777b538SAndroid Build Coastguard Worker size_t N, 169*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> 170*6777b538SAndroid Build Coastguard Worker requires(N <= std::numeric_limits<size_t>::max() / sizeof(T)) MutableSpan()171*6777b538SAndroid Build Coastguard Worker std::optional<span<T, N>> MutableSpan() { 172*6777b538SAndroid Build Coastguard Worker constexpr size_t byte_size = 173*6777b538SAndroid Build Coastguard Worker N * sizeof(T); // Overflow is checked by `requires`. 174*6777b538SAndroid Build Coastguard Worker if (byte_size > remaining_.size()) { 175*6777b538SAndroid Build Coastguard Worker return std::nullopt; 176*6777b538SAndroid Build Coastguard Worker } 177*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = remaining_.split_at(byte_size); 178*6777b538SAndroid Build Coastguard Worker remaining_ = rhs; 179*6777b538SAndroid Build Coastguard Worker // SAFETY: The byte size of `span<T>` with size `count` is `count * 180*6777b538SAndroid Build Coastguard Worker // sizeof(T)` which is exactly `byte_size`, the byte size of `lhs`. 181*6777b538SAndroid Build Coastguard Worker // 182*6777b538SAndroid Build Coastguard Worker // TODO(danakj): This is UB without creating a lifetime for the object in 183*6777b538SAndroid Build Coastguard Worker // the compiler, which we can not do before C++23: 184*6777b538SAndroid Build Coastguard Worker // https://en.cppreference.com/w/cpp/memory/start_lifetime_as 185*6777b538SAndroid Build Coastguard Worker return UNSAFE_BUFFERS(span<T, N>(reinterpret_cast<T*>(lhs.data()), N)); 186*6777b538SAndroid Build Coastguard Worker } 187*6777b538SAndroid Build Coastguard Worker 188*6777b538SAndroid Build Coastguard Worker // Returns a span to |count| const objects of type T in the buffer at the 189*6777b538SAndroid Build Coastguard Worker // current position. 190*6777b538SAndroid Build Coastguard Worker // 191*6777b538SAndroid Build Coastguard Worker // # Safety 192*6777b538SAndroid Build Coastguard Worker // Note that the buffer's current position must be aligned for the type T or 193*6777b538SAndroid Build Coastguard Worker // using the span will cause Undefined Behaviour. 194*6777b538SAndroid Build Coastguard Worker // TODO(danakj): We should probably CHECK this instead of allowing UB into 195*6777b538SAndroid Build Coastguard Worker // production. 196*6777b538SAndroid Build Coastguard Worker template <typename T, 197*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> Span(size_t count)198*6777b538SAndroid Build Coastguard Worker span<const T> Span(size_t count) { 199*6777b538SAndroid Build Coastguard Worker return MutableSpan<const T>(count); 200*6777b538SAndroid Build Coastguard Worker } 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker // An overload for when the size is known at compile time. The result will be 203*6777b538SAndroid Build Coastguard Worker // a fixed-size span. 204*6777b538SAndroid Build Coastguard Worker template <typename T, 205*6777b538SAndroid Build Coastguard Worker size_t N, 206*6777b538SAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_trivially_copyable_v<T>>> 207*6777b538SAndroid Build Coastguard Worker requires(N <= std::numeric_limits<size_t>::max() / sizeof(T)) Span()208*6777b538SAndroid Build Coastguard Worker std::optional<span<const T, N>> Span() { 209*6777b538SAndroid Build Coastguard Worker return MutableSpan<const T, N>(); 210*6777b538SAndroid Build Coastguard Worker } 211*6777b538SAndroid Build Coastguard Worker 212*6777b538SAndroid Build Coastguard Worker // Resets the iterator position to the absolute offset |to|. Seek(size_t to)213*6777b538SAndroid Build Coastguard Worker void Seek(size_t to) { remaining_ = buffer_.subspan(to); } 214*6777b538SAndroid Build Coastguard Worker 215*6777b538SAndroid Build Coastguard Worker // Limits the remaining data to the specified size. 216*6777b538SAndroid Build Coastguard Worker // Seeking to an absolute offset reverses this. TruncateTo(size_t size)217*6777b538SAndroid Build Coastguard Worker void TruncateTo(size_t size) { remaining_ = remaining_.first(size); } 218*6777b538SAndroid Build Coastguard Worker 219*6777b538SAndroid Build Coastguard Worker // Returns the total size of the underlying buffer. total_size()220*6777b538SAndroid Build Coastguard Worker size_t total_size() const { return buffer_.size(); } 221*6777b538SAndroid Build Coastguard Worker 222*6777b538SAndroid Build Coastguard Worker // Returns the current position in the buffer. position()223*6777b538SAndroid Build Coastguard Worker size_t position() const { 224*6777b538SAndroid Build Coastguard Worker // SAFETY: `remaining_` is a subspan always constructed from `buffer_` (or 225*6777b538SAndroid Build Coastguard Worker // from itself) so its `data()` pointer is always inside `buffer_`. This 226*6777b538SAndroid Build Coastguard Worker // means the subtraction is well-defined and the result is always 227*6777b538SAndroid Build Coastguard Worker // non-negative. 228*6777b538SAndroid Build Coastguard Worker return static_cast<size_t>( 229*6777b538SAndroid Build Coastguard Worker UNSAFE_BUFFERS(remaining_.data() - buffer_.data())); 230*6777b538SAndroid Build Coastguard Worker } 231*6777b538SAndroid Build Coastguard Worker 232*6777b538SAndroid Build Coastguard Worker private: 233*6777b538SAndroid Build Coastguard Worker // The original buffer that the iterator was constructed with. 234*6777b538SAndroid Build Coastguard Worker const span<B> buffer_; 235*6777b538SAndroid Build Coastguard Worker // A subspan of `buffer_` containing the remaining bytes to iterate over. 236*6777b538SAndroid Build Coastguard Worker span<B> remaining_; 237*6777b538SAndroid Build Coastguard Worker // Copy and assign allowed. 238*6777b538SAndroid Build Coastguard Worker }; 239*6777b538SAndroid Build Coastguard Worker 240*6777b538SAndroid Build Coastguard Worker } // namespace base 241*6777b538SAndroid Build Coastguard Worker 242*6777b538SAndroid Build Coastguard Worker #endif // BASE_CONTAINERS_BUFFER_ITERATOR_H_ 243