• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/pickle.h"
6 
7 #include <stdlib.h>
8 
9 #include <algorithm>  // for max()
10 
11 //------------------------------------------------------------------------------
12 
13 using base::char16;
14 using base::string16;
15 
16 // static
17 const int Pickle::kPayloadUnit = 64;
18 
19 static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
20 
PickleIterator(const Pickle & pickle)21 PickleIterator::PickleIterator(const Pickle& pickle)
22     : read_ptr_(pickle.payload()),
23       read_end_ptr_(pickle.end_of_payload()) {
24 }
25 
26 template <typename Type>
ReadBuiltinType(Type * result)27 inline bool PickleIterator::ReadBuiltinType(Type* result) {
28   const char* read_from = GetReadPointerAndAdvance<Type>();
29   if (!read_from)
30     return false;
31   if (sizeof(Type) > sizeof(uint32))
32     memcpy(result, read_from, sizeof(*result));
33   else
34     *result = *reinterpret_cast<const Type*>(read_from);
35   return true;
36 }
37 
38 template<typename Type>
GetReadPointerAndAdvance()39 inline const char* PickleIterator::GetReadPointerAndAdvance() {
40   const char* current_read_ptr = read_ptr_;
41   if (read_ptr_ + sizeof(Type) > read_end_ptr_)
42     return NULL;
43   if (sizeof(Type) < sizeof(uint32))
44     read_ptr_ += AlignInt(sizeof(Type), sizeof(uint32));
45   else
46     read_ptr_ += sizeof(Type);
47   return current_read_ptr;
48 }
49 
GetReadPointerAndAdvance(int num_bytes)50 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
51   if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes)
52     return NULL;
53   const char* current_read_ptr = read_ptr_;
54   read_ptr_ += AlignInt(num_bytes, sizeof(uint32));
55   return current_read_ptr;
56 }
57 
GetReadPointerAndAdvance(int num_elements,size_t size_element)58 inline const char* PickleIterator::GetReadPointerAndAdvance(int num_elements,
59                                                           size_t size_element) {
60   // Check for int32 overflow.
61   int64 num_bytes = static_cast<int64>(num_elements) * size_element;
62   int num_bytes32 = static_cast<int>(num_bytes);
63   if (num_bytes != static_cast<int64>(num_bytes32))
64     return NULL;
65   return GetReadPointerAndAdvance(num_bytes32);
66 }
67 
ReadBool(bool * result)68 bool PickleIterator::ReadBool(bool* result) {
69   return ReadBuiltinType(result);
70 }
71 
ReadInt(int * result)72 bool PickleIterator::ReadInt(int* result) {
73   return ReadBuiltinType(result);
74 }
75 
ReadLong(long * result)76 bool PickleIterator::ReadLong(long* result) {
77   return ReadBuiltinType(result);
78 }
79 
ReadUInt16(uint16 * result)80 bool PickleIterator::ReadUInt16(uint16* result) {
81   return ReadBuiltinType(result);
82 }
83 
ReadUInt32(uint32 * result)84 bool PickleIterator::ReadUInt32(uint32* result) {
85   return ReadBuiltinType(result);
86 }
87 
ReadInt64(int64 * result)88 bool PickleIterator::ReadInt64(int64* result) {
89   return ReadBuiltinType(result);
90 }
91 
ReadUInt64(uint64 * result)92 bool PickleIterator::ReadUInt64(uint64* result) {
93   return ReadBuiltinType(result);
94 }
95 
ReadFloat(float * result)96 bool PickleIterator::ReadFloat(float* result) {
97   // crbug.com/315213
98   // The source data may not be properly aligned, and unaligned float reads
99   // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
100   // into the result.
101   const char* read_from = GetReadPointerAndAdvance<float>();
102   if (!read_from)
103     return false;
104   memcpy(result, read_from, sizeof(*result));
105   return true;
106 }
107 
ReadString(std::string * result)108 bool PickleIterator::ReadString(std::string* result) {
109   int len;
110   if (!ReadInt(&len))
111     return false;
112   const char* read_from = GetReadPointerAndAdvance(len);
113   if (!read_from)
114     return false;
115 
116   result->assign(read_from, len);
117   return true;
118 }
119 
ReadWString(std::wstring * result)120 bool PickleIterator::ReadWString(std::wstring* result) {
121   int len;
122   if (!ReadInt(&len))
123     return false;
124   const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
125   if (!read_from)
126     return false;
127 
128   result->assign(reinterpret_cast<const wchar_t*>(read_from), len);
129   return true;
130 }
131 
ReadString16(string16 * result)132 bool PickleIterator::ReadString16(string16* result) {
133   int len;
134   if (!ReadInt(&len))
135     return false;
136   const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
137   if (!read_from)
138     return false;
139 
140   result->assign(reinterpret_cast<const char16*>(read_from), len);
141   return true;
142 }
143 
ReadData(const char ** data,int * length)144 bool PickleIterator::ReadData(const char** data, int* length) {
145   *length = 0;
146   *data = 0;
147 
148   if (!ReadInt(length))
149     return false;
150 
151   return ReadBytes(data, *length);
152 }
153 
ReadBytes(const char ** data,int length)154 bool PickleIterator::ReadBytes(const char** data, int length) {
155   const char* read_from = GetReadPointerAndAdvance(length);
156   if (!read_from)
157     return false;
158   *data = read_from;
159   return true;
160 }
161 
162 // Payload is uint32 aligned.
163 
Pickle()164 Pickle::Pickle()
165     : header_(NULL),
166       header_size_(sizeof(Header)),
167       capacity_after_header_(0),
168       write_offset_(0) {
169   Resize(kPayloadUnit);
170   header_->payload_size = 0;
171 }
172 
Pickle(int header_size)173 Pickle::Pickle(int header_size)
174     : header_(NULL),
175       header_size_(AlignInt(header_size, sizeof(uint32))),
176       capacity_after_header_(0),
177       write_offset_(0) {
178   DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
179   DCHECK_LE(header_size, kPayloadUnit);
180   Resize(kPayloadUnit);
181   header_->payload_size = 0;
182 }
183 
Pickle(const char * data,int data_len)184 Pickle::Pickle(const char* data, int data_len)
185     : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
186       header_size_(0),
187       capacity_after_header_(kCapacityReadOnly),
188       write_offset_(0) {
189   if (data_len >= static_cast<int>(sizeof(Header)))
190     header_size_ = data_len - header_->payload_size;
191 
192   if (header_size_ > static_cast<unsigned int>(data_len))
193     header_size_ = 0;
194 
195   if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
196     header_size_ = 0;
197 
198   // If there is anything wrong with the data, we're not going to use it.
199   if (!header_size_)
200     header_ = NULL;
201 }
202 
Pickle(const Pickle & other)203 Pickle::Pickle(const Pickle& other)
204     : header_(NULL),
205       header_size_(other.header_size_),
206       capacity_after_header_(0),
207       write_offset_(other.write_offset_) {
208   size_t payload_size = header_size_ + other.header_->payload_size;
209   Resize(payload_size);
210   memcpy(header_, other.header_, payload_size);
211 }
212 
~Pickle()213 Pickle::~Pickle() {
214   if (capacity_after_header_ != kCapacityReadOnly)
215     free(header_);
216 }
217 
operator =(const Pickle & other)218 Pickle& Pickle::operator=(const Pickle& other) {
219   if (this == &other) {
220     NOTREACHED();
221     return *this;
222   }
223   if (capacity_after_header_ == kCapacityReadOnly) {
224     header_ = NULL;
225     capacity_after_header_ = 0;
226   }
227   if (header_size_ != other.header_size_) {
228     free(header_);
229     header_ = NULL;
230     header_size_ = other.header_size_;
231   }
232   Resize(other.header_->payload_size);
233   memcpy(header_, other.header_,
234          other.header_size_ + other.header_->payload_size);
235   write_offset_ = other.write_offset_;
236   return *this;
237 }
238 
WriteString(const std::string & value)239 bool Pickle::WriteString(const std::string& value) {
240   if (!WriteInt(static_cast<int>(value.size())))
241     return false;
242 
243   return WriteBytes(value.data(), static_cast<int>(value.size()));
244 }
245 
WriteWString(const std::wstring & value)246 bool Pickle::WriteWString(const std::wstring& value) {
247   if (!WriteInt(static_cast<int>(value.size())))
248     return false;
249 
250   return WriteBytes(value.data(),
251                     static_cast<int>(value.size() * sizeof(wchar_t)));
252 }
253 
WriteString16(const string16 & value)254 bool Pickle::WriteString16(const string16& value) {
255   if (!WriteInt(static_cast<int>(value.size())))
256     return false;
257 
258   return WriteBytes(value.data(),
259                     static_cast<int>(value.size()) * sizeof(char16));
260 }
261 
WriteData(const char * data,int length)262 bool Pickle::WriteData(const char* data, int length) {
263   return length >= 0 && WriteInt(length) && WriteBytes(data, length);
264 }
265 
WriteBytes(const void * data,int length)266 bool Pickle::WriteBytes(const void* data, int length) {
267   WriteBytesCommon(data, length);
268   return true;
269 }
270 
Reserve(size_t length)271 void Pickle::Reserve(size_t length) {
272   size_t data_len = AlignInt(length, sizeof(uint32));
273   DCHECK_GE(data_len, length);
274 #ifdef ARCH_CPU_64_BITS
275   DCHECK_LE(data_len, kuint32max);
276 #endif
277   DCHECK_LE(write_offset_, kuint32max - data_len);
278   size_t new_size = write_offset_ + data_len;
279   if (new_size > capacity_after_header_)
280     Resize(capacity_after_header_ * 2 + new_size);
281 }
282 
Resize(size_t new_capacity)283 void Pickle::Resize(size_t new_capacity) {
284   new_capacity = AlignInt(new_capacity, kPayloadUnit);
285 
286   CHECK_NE(capacity_after_header_, kCapacityReadOnly);
287   void* p = realloc(header_, header_size_ + new_capacity);
288   CHECK(p);
289   header_ = reinterpret_cast<Header*>(p);
290   capacity_after_header_ = new_capacity;
291 }
292 
293 // static
FindNext(size_t header_size,const char * start,const char * end)294 const char* Pickle::FindNext(size_t header_size,
295                              const char* start,
296                              const char* end) {
297   DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
298   DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
299 
300   size_t length = static_cast<size_t>(end - start);
301   if (length < sizeof(Header))
302     return NULL;
303 
304   const Header* hdr = reinterpret_cast<const Header*>(start);
305   if (length < header_size || length - header_size < hdr->payload_size)
306     return NULL;
307   return start + header_size + hdr->payload_size;
308 }
309 
WriteBytesStatic(const void * data)310 template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
311   WriteBytesCommon(data, length);
312 }
313 
314 template void Pickle::WriteBytesStatic<2>(const void* data);
315 template void Pickle::WriteBytesStatic<4>(const void* data);
316 template void Pickle::WriteBytesStatic<8>(const void* data);
317 
WriteBytesCommon(const void * data,size_t length)318 inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
319   DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
320       << "oops: pickle is readonly";
321   size_t data_len = AlignInt(length, sizeof(uint32));
322   DCHECK_GE(data_len, length);
323 #ifdef ARCH_CPU_64_BITS
324   DCHECK_LE(data_len, kuint32max);
325 #endif
326   DCHECK_LE(write_offset_, kuint32max - data_len);
327   size_t new_size = write_offset_ + data_len;
328   if (new_size > capacity_after_header_) {
329     Resize(std::max(capacity_after_header_ * 2, new_size));
330   }
331 
332   char* write = mutable_payload() + write_offset_;
333   memcpy(write, data, length);
334   memset(write + length, 0, data_len - length);
335   header_->payload_size = static_cast<uint32>(write_offset_ + length);
336   write_offset_ = new_size;
337 }
338