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