1 /* 2 * Copyright (C) 2017 The Android Open Source Project 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 #pragma once 18 19 #include "common.h" 20 #include "arrayview.h" 21 #include "memview.h" 22 #include "dex_leb128.h" 23 24 #include <assert.h> 25 #include <string> 26 #include <algorithm> 27 #include <vector> 28 #include <cstring> 29 30 namespace slicer { 31 32 // A simple growing memory buffer 33 // 34 // NOTE: pointers into this buffer are not stable 35 // since it may be relocated as it expands. 36 // 37 class Buffer { 38 public: 39 Buffer() = default; 40 ~Buffer()41 ~Buffer() { Free(); } 42 43 Buffer(const Buffer&) = delete; 44 Buffer& operator=(const Buffer&) = delete; 45 Buffer(Buffer && b)46 Buffer(Buffer&& b) { 47 std::swap(buff_, b.buff_); 48 std::swap(size_, b.size_); 49 std::swap(capacity_, b.capacity_); 50 } 51 52 Buffer& operator=(Buffer&& b) { 53 Free(); 54 std::swap(buff_, b.buff_); 55 std::swap(size_, b.size_); 56 std::swap(capacity_, b.capacity_); 57 return *this; 58 } 59 60 public: 61 // Align the total size and prevent further changes Seal(size_t alignment)62 size_t Seal(size_t alignment) { 63 SLICER_CHECK(!sealed_); 64 Align(alignment); 65 sealed_ = true; 66 return size(); 67 } 68 69 // Returns a pointer within the buffer 70 // 71 // NOTE: the returned pointer is "ephemeral" and 72 // is only valid until the next buffer push/alloc 73 // 74 template <class T> ptr(size_t offset)75 T* ptr(size_t offset) { 76 SLICER_CHECK(offset + sizeof(T) <= size_); 77 return reinterpret_cast<T*>(buff_ + offset); 78 } 79 80 // Align the buffer size to the specified alignment Align(size_t alignment)81 void Align(size_t alignment) { 82 assert(alignment > 0); 83 size_t rem = size_ % alignment; 84 if (rem != 0) { 85 Alloc(alignment - rem); 86 } 87 } 88 Alloc(size_t size)89 size_t Alloc(size_t size) { 90 size_t offset = size_; 91 Expand(size); 92 std::memset(buff_ + offset, 0, size); 93 return offset; 94 } 95 Push(const void * ptr,size_t size)96 size_t Push(const void* ptr, size_t size) { 97 size_t offset = size_; 98 Expand(size); 99 std::memcpy(buff_ + offset, ptr, size); 100 return offset; 101 } 102 Push(const MemView & memView)103 size_t Push(const MemView& memView) { 104 return Push(memView.ptr(), memView.size()); 105 } 106 107 template <class T> Push(const ArrayView<T> & a)108 size_t Push(const ArrayView<T>& a) { 109 return Push(a.data(), a.size() * sizeof(T)); 110 } 111 112 template <class T> Push(const std::vector<T> & v)113 size_t Push(const std::vector<T>& v) { 114 return Push(v.data(), v.size() * sizeof(T)); 115 } 116 Push(const Buffer & buff)117 size_t Push(const Buffer& buff) { 118 SLICER_CHECK(&buff != this); 119 return Push(buff.data(), buff.size()); 120 } 121 122 // TODO: this is really dangerous since it would 123 // write any type - sometimes not what you expect. 124 // 125 template <class T> Push(const T & value)126 size_t Push(const T& value) { 127 return Push(&value, sizeof(value)); 128 } 129 PushULeb128(dex::u4 value)130 size_t PushULeb128(dex::u4 value) { 131 dex::u1 tmp[4]; 132 dex::u1* end = dex::WriteULeb128(tmp, value); 133 assert(end > tmp && end - tmp <= 4); 134 return Push(tmp, end - tmp); 135 } 136 PushSLeb128(dex::s4 value)137 size_t PushSLeb128(dex::s4 value) { 138 dex::u1 tmp[4]; 139 dex::u1* end = dex::WriteSLeb128(tmp, value); 140 assert(end > tmp && end - tmp <= 4); 141 return Push(tmp, end - tmp); 142 } 143 size()144 size_t size() const { return size_; } 145 empty()146 bool empty() const { return size_ == 0; } 147 Free()148 void Free() { 149 ::free(buff_); 150 buff_ = nullptr; 151 size_ = 0; 152 capacity_ = 0; 153 } 154 data()155 const dex::u1* data() const { 156 SLICER_CHECK(buff_ != nullptr); 157 return buff_; 158 } 159 160 private: Expand(size_t size)161 void Expand(size_t size) { 162 SLICER_CHECK(!sealed_); 163 if (size_ + size > capacity_) { 164 capacity_ = std::max(size_t(capacity_ * 1.5), size_ + size); 165 buff_ = static_cast<dex::u1*>(::realloc(buff_, capacity_)); 166 SLICER_CHECK(buff_ != nullptr); 167 } 168 size_ += size; 169 } 170 171 private: 172 dex::u1* buff_ = nullptr; 173 size_t size_ = 0; 174 size_t capacity_ = 0; 175 bool sealed_ = false; 176 }; 177 178 } // namespace slicer 179 180