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