github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/executor/_include/flatbuffers/vector_downward.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_VECTOR_DOWNWARD_H_
    18  #define FLATBUFFERS_VECTOR_DOWNWARD_H_
    19  
    20  #include "flatbuffers/base.h"
    21  #include "flatbuffers/default_allocator.h"
    22  #include "flatbuffers/detached_buffer.h"
    23  
    24  namespace flatbuffers {
    25  
    26  // This is a minimal replication of std::vector<uint8_t> functionality,
    27  // except growing from higher to lower addresses. i.e. push_back() inserts data
    28  // in the lowest address in the vector.
    29  // Since this vector leaves the lower part unused, we support a "scratch-pad"
    30  // that can be stored there for temporary data, to share the allocated space.
    31  // Essentially, this supports 2 std::vectors in a single buffer.
    32  class vector_downward {
    33   public:
    34    explicit vector_downward(size_t initial_size, Allocator *allocator,
    35                             bool own_allocator, size_t buffer_minalign)
    36        : allocator_(allocator),
    37          own_allocator_(own_allocator),
    38          initial_size_(initial_size),
    39          buffer_minalign_(buffer_minalign),
    40          reserved_(0),
    41          size_(0),
    42          buf_(nullptr),
    43          cur_(nullptr),
    44          scratch_(nullptr) {}
    45  
    46    vector_downward(vector_downward &&other)
    47        // clang-format on
    48        : allocator_(other.allocator_),
    49          own_allocator_(other.own_allocator_),
    50          initial_size_(other.initial_size_),
    51          buffer_minalign_(other.buffer_minalign_),
    52          reserved_(other.reserved_),
    53          size_(other.size_),
    54          buf_(other.buf_),
    55          cur_(other.cur_),
    56          scratch_(other.scratch_) {
    57      // No change in other.allocator_
    58      // No change in other.initial_size_
    59      // No change in other.buffer_minalign_
    60      other.own_allocator_ = false;
    61      other.reserved_ = 0;
    62      other.buf_ = nullptr;
    63      other.cur_ = nullptr;
    64      other.scratch_ = nullptr;
    65    }
    66  
    67    vector_downward &operator=(vector_downward &&other) {
    68      // Move construct a temporary and swap idiom
    69      vector_downward temp(std::move(other));
    70      swap(temp);
    71      return *this;
    72    }
    73  
    74    ~vector_downward() {
    75      clear_buffer();
    76      clear_allocator();
    77    }
    78  
    79    void reset() {
    80      clear_buffer();
    81      clear();
    82    }
    83  
    84    void clear() {
    85      if (buf_) {
    86        cur_ = buf_ + reserved_;
    87      } else {
    88        reserved_ = 0;
    89        cur_ = nullptr;
    90      }
    91      size_ = 0;
    92      clear_scratch();
    93    }
    94  
    95    void clear_scratch() { scratch_ = buf_; }
    96  
    97    void clear_allocator() {
    98      if (own_allocator_ && allocator_) { delete allocator_; }
    99      allocator_ = nullptr;
   100      own_allocator_ = false;
   101    }
   102  
   103    void clear_buffer() {
   104      if (buf_) Deallocate(allocator_, buf_, reserved_);
   105      buf_ = nullptr;
   106    }
   107  
   108    // Relinquish the pointer to the caller.
   109    uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
   110      auto *buf = buf_;
   111      allocated_bytes = reserved_;
   112      offset = static_cast<size_t>(cur_ - buf_);
   113  
   114      // release_raw only relinquishes the buffer ownership.
   115      // Does not deallocate or reset the allocator. Destructor will do that.
   116      buf_ = nullptr;
   117      clear();
   118      return buf;
   119    }
   120  
   121    // Relinquish the pointer to the caller.
   122    DetachedBuffer release() {
   123      // allocator ownership (if any) is transferred to DetachedBuffer.
   124      DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
   125                        size());
   126      if (own_allocator_) {
   127        allocator_ = nullptr;
   128        own_allocator_ = false;
   129      }
   130      buf_ = nullptr;
   131      clear();
   132      return fb;
   133    }
   134  
   135    size_t ensure_space(size_t len) {
   136      FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
   137      if (len > static_cast<size_t>(cur_ - scratch_)) { reallocate(len); }
   138      // Beyond this, signed offsets may not have enough range:
   139      // (FlatBuffers > 2GB not supported).
   140      FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
   141      return len;
   142    }
   143  
   144    inline uint8_t *make_space(size_t len) {
   145      if (len) {
   146        ensure_space(len);
   147        cur_ -= len;
   148        size_ += static_cast<uoffset_t>(len);
   149      }
   150      return cur_;
   151    }
   152  
   153    // Returns nullptr if using the DefaultAllocator.
   154    Allocator *get_custom_allocator() { return allocator_; }
   155  
   156    inline uoffset_t size() const { return size_; }
   157  
   158    uoffset_t scratch_size() const {
   159      return static_cast<uoffset_t>(scratch_ - buf_);
   160    }
   161  
   162    size_t capacity() const { return reserved_; }
   163  
   164    uint8_t *data() const {
   165      FLATBUFFERS_ASSERT(cur_);
   166      return cur_;
   167    }
   168  
   169    uint8_t *scratch_data() const {
   170      FLATBUFFERS_ASSERT(buf_);
   171      return buf_;
   172    }
   173  
   174    uint8_t *scratch_end() const {
   175      FLATBUFFERS_ASSERT(scratch_);
   176      return scratch_;
   177    }
   178  
   179    uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
   180  
   181    void push(const uint8_t *bytes, size_t num) {
   182      if (num > 0) { memcpy(make_space(num), bytes, num); }
   183    }
   184  
   185    // Specialized version of push() that avoids memcpy call for small data.
   186    template<typename T> void push_small(const T &little_endian_t) {
   187      make_space(sizeof(T));
   188      *reinterpret_cast<T *>(cur_) = little_endian_t;
   189    }
   190  
   191    template<typename T> void scratch_push_small(const T &t) {
   192      ensure_space(sizeof(T));
   193      *reinterpret_cast<T *>(scratch_) = t;
   194      scratch_ += sizeof(T);
   195    }
   196  
   197    // fill() is most frequently called with small byte counts (<= 4),
   198    // which is why we're using loops rather than calling memset.
   199    void fill(size_t zero_pad_bytes) {
   200      make_space(zero_pad_bytes);
   201      for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
   202    }
   203  
   204    // Version for when we know the size is larger.
   205    // Precondition: zero_pad_bytes > 0
   206    void fill_big(size_t zero_pad_bytes) {
   207      memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
   208    }
   209  
   210    void pop(size_t bytes_to_remove) {
   211      cur_ += bytes_to_remove;
   212      size_ -= static_cast<uoffset_t>(bytes_to_remove);
   213    }
   214  
   215    void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
   216  
   217    void swap(vector_downward &other) {
   218      using std::swap;
   219      swap(allocator_, other.allocator_);
   220      swap(own_allocator_, other.own_allocator_);
   221      swap(initial_size_, other.initial_size_);
   222      swap(buffer_minalign_, other.buffer_minalign_);
   223      swap(reserved_, other.reserved_);
   224      swap(size_, other.size_);
   225      swap(buf_, other.buf_);
   226      swap(cur_, other.cur_);
   227      swap(scratch_, other.scratch_);
   228    }
   229  
   230    void swap_allocator(vector_downward &other) {
   231      using std::swap;
   232      swap(allocator_, other.allocator_);
   233      swap(own_allocator_, other.own_allocator_);
   234    }
   235  
   236   private:
   237    // You shouldn't really be copying instances of this class.
   238    FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &));
   239    FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &));
   240  
   241    Allocator *allocator_;
   242    bool own_allocator_;
   243    size_t initial_size_;
   244    size_t buffer_minalign_;
   245    size_t reserved_;
   246    uoffset_t size_;
   247    uint8_t *buf_;
   248    uint8_t *cur_;  // Points at location between empty (below) and used (above).
   249    uint8_t *scratch_;  // Points to the end of the scratchpad in use.
   250  
   251    void reallocate(size_t len) {
   252      auto old_reserved = reserved_;
   253      auto old_size = size();
   254      auto old_scratch_size = scratch_size();
   255      reserved_ +=
   256          (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
   257      reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
   258      if (buf_) {
   259        buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
   260                                  old_size, old_scratch_size);
   261      } else {
   262        buf_ = Allocate(allocator_, reserved_);
   263      }
   264      cur_ = buf_ + reserved_ - old_size;
   265      scratch_ = buf_ + old_scratch_size;
   266    }
   267  };
   268  
   269  }  // namespace flatbuffers
   270  
   271  #endif  // FLATBUFFERS_VECTOR_DOWNWARD_H_