blob: d83391bb524194b212a1f86ea0da26c1befd84ea [file] [log] [blame]
jbates@chromium.org0fc87362012-03-08 05:42:56 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
initial.commit3f4a7322008-07-27 06:49:38 +09005#include "base/pickle.h"
6
maruel@google.com825f8792008-08-07 05:35:17 +09007#include <stdlib.h>
8
thestig@chromium.orgeb9afb42009-10-28 13:21:01 +09009#include <algorithm> // for max()
dskibaaa08dcb2015-10-01 02:24:30 +090010#include <limits>
maruel@google.com825f8792008-08-07 05:35:17 +090011
primiano47c69062015-07-25 05:13:32 +090012#include "base/bits.h"
13#include "base/macros.h"
avia6a6a682015-12-27 07:15:14 +090014#include "build/build_config.h"
primiano47c69062015-07-25 05:13:32 +090015
brettwd0d62652015-06-04 01:20:14 +090016namespace base {
brettw@chromium.org5b040852013-12-03 09:39:26 +090017
initial.commit3f4a7322008-07-27 06:49:38 +090018// static
19const int Pickle::kPayloadUnit = 64;
20
thestig@chromium.orgf0c8f442011-10-11 07:20:33 +090021static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
deanm@google.com19650de2008-08-13 23:57:51 +090022
jbates@chromium.org0fc87362012-03-08 05:42:56 +090023PickleIterator::PickleIterator(const Pickle& pickle)
halyavin@google.com0398c722014-06-03 08:23:49 +090024 : payload_(pickle.payload()),
25 read_index_(0),
26 end_index_(pickle.payload_size()) {
jbates@chromium.org0fc87362012-03-08 05:42:56 +090027}
28
29template <typename Type>
30inline bool PickleIterator::ReadBuiltinType(Type* result) {
31 const char* read_from = GetReadPointerAndAdvance<Type>();
32 if (!read_from)
33 return false;
avi27b40072015-12-05 07:38:52 +090034 if (sizeof(Type) > sizeof(uint32_t))
jbates@chromium.org0fc87362012-03-08 05:42:56 +090035 memcpy(result, read_from, sizeof(*result));
36 else
37 *result = *reinterpret_cast<const Type*>(read_from);
38 return true;
39}
40
halyavin@google.com0398c722014-06-03 08:23:49 +090041inline void PickleIterator::Advance(size_t size) {
primiano47c69062015-07-25 05:13:32 +090042 size_t aligned_size = bits::Align(size, sizeof(uint32_t));
halyavin@google.com0398c722014-06-03 08:23:49 +090043 if (end_index_ - read_index_ < aligned_size) {
44 read_index_ = end_index_;
45 } else {
46 read_index_ += aligned_size;
47 }
48}
49
jbates@chromium.org0fc87362012-03-08 05:42:56 +090050template<typename Type>
51inline const char* PickleIterator::GetReadPointerAndAdvance() {
halyavin@google.com0398c722014-06-03 08:23:49 +090052 if (sizeof(Type) > end_index_ - read_index_) {
53 read_index_ = end_index_;
jbates@chromium.org0fc87362012-03-08 05:42:56 +090054 return NULL;
halyavin@google.com0398c722014-06-03 08:23:49 +090055 }
56 const char* current_read_ptr = payload_ + read_index_;
57 Advance(sizeof(Type));
jbates@chromium.org0fc87362012-03-08 05:42:56 +090058 return current_read_ptr;
59}
60
61const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
halyavin@google.com0398c722014-06-03 08:23:49 +090062 if (num_bytes < 0 ||
63 end_index_ - read_index_ < static_cast<size_t>(num_bytes)) {
64 read_index_ = end_index_;
glider@chromium.orgfcfb8252012-03-14 02:17:56 +090065 return NULL;
halyavin@google.com0398c722014-06-03 08:23:49 +090066 }
67 const char* current_read_ptr = payload_ + read_index_;
68 Advance(num_bytes);
jbates@chromium.org0fc87362012-03-08 05:42:56 +090069 return current_read_ptr;
70}
71
halyavin@google.com0398c722014-06-03 08:23:49 +090072inline const char* PickleIterator::GetReadPointerAndAdvance(
73 int num_elements,
74 size_t size_element) {
avia6a6a682015-12-27 07:15:14 +090075 // Check for int32_t overflow.
avi27b40072015-12-05 07:38:52 +090076 int64_t num_bytes = static_cast<int64_t>(num_elements) * size_element;
jbates@chromium.org0fc87362012-03-08 05:42:56 +090077 int num_bytes32 = static_cast<int>(num_bytes);
avi27b40072015-12-05 07:38:52 +090078 if (num_bytes != static_cast<int64_t>(num_bytes32))
jbates@chromium.org0fc87362012-03-08 05:42:56 +090079 return NULL;
80 return GetReadPointerAndAdvance(num_bytes32);
81}
82
83bool PickleIterator::ReadBool(bool* result) {
84 return ReadBuiltinType(result);
85}
86
87bool PickleIterator::ReadInt(int* result) {
88 return ReadBuiltinType(result);
89}
90
91bool PickleIterator::ReadLong(long* result) {
92 return ReadBuiltinType(result);
93}
94
avi27b40072015-12-05 07:38:52 +090095bool PickleIterator::ReadUInt16(uint16_t* result) {
jbates@chromium.org0fc87362012-03-08 05:42:56 +090096 return ReadBuiltinType(result);
97}
98
avi27b40072015-12-05 07:38:52 +090099bool PickleIterator::ReadUInt32(uint32_t* result) {
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900100 return ReadBuiltinType(result);
101}
102
avi27b40072015-12-05 07:38:52 +0900103bool PickleIterator::ReadInt64(int64_t* result) {
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900104 return ReadBuiltinType(result);
105}
106
avi27b40072015-12-05 07:38:52 +0900107bool PickleIterator::ReadUInt64(uint64_t* result) {
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900108 return ReadBuiltinType(result);
109}
110
pkasting7ed1f882014-10-02 12:01:04 +0900111bool PickleIterator::ReadSizeT(size_t* result) {
112 // Always read size_t as a 64-bit value to ensure compatibility between 32-bit
113 // and 64-bit processes.
avi27b40072015-12-05 07:38:52 +0900114 uint64_t result_uint64 = 0;
pkasting7ed1f882014-10-02 12:01:04 +0900115 bool success = ReadBuiltinType(&result_uint64);
116 *result = static_cast<size_t>(result_uint64);
117 // Fail if the cast above truncates the value.
118 return success && (*result == result_uint64);
119}
120
rbyers@chromium.orga1f0b982012-11-29 00:40:58 +0900121bool PickleIterator::ReadFloat(float* result) {
piman@chromium.org2135b962013-11-18 09:50:25 +0900122 // crbug.com/315213
123 // The source data may not be properly aligned, and unaligned float 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<float>();
127 if (!read_from)
128 return false;
129 memcpy(result, read_from, sizeof(*result));
130 return true;
rbyers@chromium.orga1f0b982012-11-29 00:40:58 +0900131}
132
mostynb@opera.comf0b78532014-07-15 07:50:32 +0900133bool PickleIterator::ReadDouble(double* result) {
134 // crbug.com/315213
135 // The source data may not be properly aligned, and unaligned double reads
136 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
137 // into the result.
138 const char* read_from = GetReadPointerAndAdvance<double>();
139 if (!read_from)
140 return false;
141 memcpy(result, read_from, sizeof(*result));
142 return true;
143}
144
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900145bool PickleIterator::ReadString(std::string* result) {
146 int len;
147 if (!ReadInt(&len))
148 return false;
149 const char* read_from = GetReadPointerAndAdvance(len);
150 if (!read_from)
151 return false;
152
153 result->assign(read_from, len);
154 return true;
155}
156
brettwd0d62652015-06-04 01:20:14 +0900157bool PickleIterator::ReadStringPiece(StringPiece* result) {
brucedawson0fff3892015-03-10 10:46:50 +0900158 int len;
159 if (!ReadInt(&len))
160 return false;
161 const char* read_from = GetReadPointerAndAdvance(len);
162 if (!read_from)
163 return false;
164
brettwd0d62652015-06-04 01:20:14 +0900165 *result = StringPiece(read_from, len);
brucedawson0fff3892015-03-10 10:46:50 +0900166 return true;
167}
168
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900169bool PickleIterator::ReadString16(string16* result) {
170 int len;
171 if (!ReadInt(&len))
172 return false;
173 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
174 if (!read_from)
175 return false;
176
177 result->assign(reinterpret_cast<const char16*>(read_from), len);
178 return true;
179}
180
brettwd0d62652015-06-04 01:20:14 +0900181bool PickleIterator::ReadStringPiece16(StringPiece16* result) {
brucedawson0fff3892015-03-10 10:46:50 +0900182 int len;
183 if (!ReadInt(&len))
184 return false;
185 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
186 if (!read_from)
187 return false;
188
brettwd0d62652015-06-04 01:20:14 +0900189 *result = StringPiece16(reinterpret_cast<const char16*>(read_from), len);
brucedawson0fff3892015-03-10 10:46:50 +0900190 return true;
191}
192
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900193bool PickleIterator::ReadData(const char** data, int* length) {
194 *length = 0;
195 *data = 0;
196
197 if (!ReadInt(length))
198 return false;
199
200 return ReadBytes(data, *length);
201}
202
203bool PickleIterator::ReadBytes(const char** data, int length) {
204 const char* read_from = GetReadPointerAndAdvance(length);
205 if (!read_from)
206 return false;
207 *data = read_from;
208 return true;
209}
210
avi27b40072015-12-05 07:38:52 +0900211// Payload is uint32_t aligned.
initial.commit3f4a7322008-07-27 06:49:38 +0900212
213Pickle::Pickle()
214 : header_(NULL),
215 header_size_(sizeof(Header)),
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900216 capacity_after_header_(0),
217 write_offset_(0) {
primiano47c69062015-07-25 05:13:32 +0900218 static_assert((Pickle::kPayloadUnit & (Pickle::kPayloadUnit - 1)) == 0,
219 "Pickle::kPayloadUnit must be a power of two");
initial.commit3f4a7322008-07-27 06:49:38 +0900220 Resize(kPayloadUnit);
221 header_->payload_size = 0;
222}
223
224Pickle::Pickle(int header_size)
225 : header_(NULL),
avi27b40072015-12-05 07:38:52 +0900226 header_size_(bits::Align(header_size, sizeof(uint32_t))),
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900227 capacity_after_header_(0),
228 write_offset_(0) {
pkasting@chromium.orgd23fe1a2011-04-01 05:34:25 +0900229 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
kushi.p@gmail.come4869772011-04-22 22:13:07 +0900230 DCHECK_LE(header_size, kPayloadUnit);
initial.commit3f4a7322008-07-27 06:49:38 +0900231 Resize(kPayloadUnit);
232 header_->payload_size = 0;
233}
234
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900235Pickle::Pickle(const char* data, int data_len)
initial.commit3f4a7322008-07-27 06:49:38 +0900236 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
rvargas@google.com8d9b2b92010-11-16 04:31:23 +0900237 header_size_(0),
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900238 capacity_after_header_(kCapacityReadOnly),
239 write_offset_(0) {
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900240 if (data_len >= static_cast<int>(sizeof(Header)))
rvargas@google.com8d9b2b92010-11-16 04:31:23 +0900241 header_size_ = data_len - header_->payload_size;
242
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900243 if (header_size_ > static_cast<unsigned int>(data_len))
rvargas@google.com8d9b2b92010-11-16 04:31:23 +0900244 header_size_ = 0;
245
avi27b40072015-12-05 07:38:52 +0900246 if (header_size_ != bits::Align(header_size_, sizeof(uint32_t)))
rvargas@google.com8d9b2b92010-11-16 04:31:23 +0900247 header_size_ = 0;
248
249 // If there is anything wrong with the data, we're not going to use it.
250 if (!header_size_)
251 header_ = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +0900252}
253
254Pickle::Pickle(const Pickle& other)
255 : header_(NULL),
256 header_size_(other.header_size_),
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900257 capacity_after_header_(0),
258 write_offset_(other.write_offset_) {
erikchenb2ca7762015-09-09 08:36:29 +0900259 Resize(other.header_->payload_size);
260 memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
initial.commit3f4a7322008-07-27 06:49:38 +0900261}
262
263Pickle::~Pickle() {
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900264 if (capacity_after_header_ != kCapacityReadOnly)
initial.commit3f4a7322008-07-27 06:49:38 +0900265 free(header_);
266}
267
268Pickle& Pickle::operator=(const Pickle& other) {
jar@chromium.org4e105f12009-08-08 08:13:35 +0900269 if (this == &other) {
270 NOTREACHED();
271 return *this;
272 }
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900273 if (capacity_after_header_ == kCapacityReadOnly) {
jar@chromium.org766c5a02009-08-03 16:01:47 +0900274 header_ = NULL;
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900275 capacity_after_header_ = 0;
jar@chromium.org766c5a02009-08-03 16:01:47 +0900276 }
277 if (header_size_ != other.header_size_) {
initial.commit3f4a7322008-07-27 06:49:38 +0900278 free(header_);
279 header_ = NULL;
280 header_size_ = other.header_size_;
281 }
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900282 Resize(other.header_->payload_size);
jar@chromium.org4e105f12009-08-08 08:13:35 +0900283 memcpy(header_, other.header_,
284 other.header_size_ + other.header_->payload_size);
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900285 write_offset_ = other.write_offset_;
initial.commit3f4a7322008-07-27 06:49:38 +0900286 return *this;
287}
288
brettwd0d62652015-06-04 01:20:14 +0900289bool Pickle::WriteString(const StringPiece& value) {
initial.commit3f4a7322008-07-27 06:49:38 +0900290 if (!WriteInt(static_cast<int>(value.size())))
291 return false;
292
293 return WriteBytes(value.data(), static_cast<int>(value.size()));
294}
295
brettwd0d62652015-06-04 01:20:14 +0900296bool Pickle::WriteString16(const StringPiece16& value) {
estade@chromium.org38a18bf2009-03-04 12:36:36 +0900297 if (!WriteInt(static_cast<int>(value.size())))
298 return false;
299
300 return WriteBytes(value.data(),
301 static_cast<int>(value.size()) * sizeof(char16));
initial.commit3f4a7322008-07-27 06:49:38 +0900302}
303
304bool Pickle::WriteData(const char* data, int length) {
wtc@chromium.orgc2f15c52009-07-29 06:00:03 +0900305 return length >= 0 && WriteInt(length) && WriteBytes(data, length);
initial.commit3f4a7322008-07-27 06:49:38 +0900306}
307
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900308bool Pickle::WriteBytes(const void* data, int length) {
309 WriteBytesCommon(data, length);
erg@google.com67a25432011-01-08 05:23:43 +0900310 return true;
311}
312
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900313void Pickle::Reserve(size_t length) {
avi27b40072015-12-05 07:38:52 +0900314 size_t data_len = bits::Align(length, sizeof(uint32_t));
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900315 DCHECK_GE(data_len, length);
erg@google.com67a25432011-01-08 05:23:43 +0900316#ifdef ARCH_CPU_64_BITS
avi27b40072015-12-05 07:38:52 +0900317 DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
erg@google.com67a25432011-01-08 05:23:43 +0900318#endif
avi27b40072015-12-05 07:38:52 +0900319 DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900320 size_t new_size = write_offset_ + data_len;
321 if (new_size > capacity_after_header_)
322 Resize(capacity_after_header_ * 2 + new_size);
erg@google.com67a25432011-01-08 05:23:43 +0900323}
324
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900325void Pickle::Resize(size_t new_capacity) {
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900326 CHECK_NE(capacity_after_header_, kCapacityReadOnly);
primiano47c69062015-07-25 05:13:32 +0900327 capacity_after_header_ = bits::Align(new_capacity, kPayloadUnit);
primiano03f77502015-06-12 06:40:10 +0900328 void* p = realloc(header_, GetTotalAllocatedSize());
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900329 CHECK(p);
initial.commit3f4a7322008-07-27 06:49:38 +0900330 header_ = reinterpret_cast<Header*>(p);
primiano03f77502015-06-12 06:40:10 +0900331}
332
rockot76180b02015-12-17 15:19:49 +0900333void* Pickle::ClaimBytes(size_t num_bytes) {
334 void* p = ClaimUninitializedBytesInternal(num_bytes);
335 CHECK(p);
336 memset(p, 0, num_bytes);
337 return p;
338}
339
primiano03f77502015-06-12 06:40:10 +0900340size_t Pickle::GetTotalAllocatedSize() const {
341 if (capacity_after_header_ == kCapacityReadOnly)
342 return 0;
343 return header_size_ + capacity_after_header_;
initial.commit3f4a7322008-07-27 06:49:38 +0900344}
345
346// static
347const char* Pickle::FindNext(size_t header_size,
348 const char* start,
349 const char* end) {
dskibaaa08dcb2015-10-01 02:24:30 +0900350 size_t pickle_size = 0;
351 if (!PeekNext(header_size, start, end, &pickle_size))
352 return NULL;
353
354 if (pickle_size > static_cast<size_t>(end - start))
355 return NULL;
356
357 return start + pickle_size;
358}
359
360// static
361bool Pickle::PeekNext(size_t header_size,
362 const char* start,
363 const char* end,
364 size_t* pickle_size) {
avi27b40072015-12-05 07:38:52 +0900365 DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32_t)));
dskibaaa08dcb2015-10-01 02:24:30 +0900366 DCHECK_GE(header_size, sizeof(Header));
kushi.p@gmail.come4869772011-04-22 22:13:07 +0900367 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
initial.commit3f4a7322008-07-27 06:49:38 +0900368
halyavin@google.com893e5bb2013-11-01 18:06:26 +0900369 size_t length = static_cast<size_t>(end - start);
370 if (length < sizeof(Header))
dskibaaa08dcb2015-10-01 02:24:30 +0900371 return false;
glider@chromium.org8b725fa2011-01-26 22:02:27 +0900372
initial.commit3f4a7322008-07-27 06:49:38 +0900373 const Header* hdr = reinterpret_cast<const Header*>(start);
dskibaaa08dcb2015-10-01 02:24:30 +0900374 if (length < header_size)
375 return false;
376
377 if (hdr->payload_size > std::numeric_limits<size_t>::max() - header_size) {
378 // If payload_size causes an overflow, we return maximum possible
379 // pickle size to indicate that.
380 *pickle_size = std::numeric_limits<size_t>::max();
381 } else {
382 *pickle_size = header_size + hdr->payload_size;
383 }
384 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900385}
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900386
387template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
388 WriteBytesCommon(data, length);
389}
390
391template void Pickle::WriteBytesStatic<2>(const void* data);
392template void Pickle::WriteBytesStatic<4>(const void* data);
393template void Pickle::WriteBytesStatic<8>(const void* data);
394
rockot76180b02015-12-17 15:19:49 +0900395inline void* Pickle::ClaimUninitializedBytesInternal(size_t length) {
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900396 DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
397 << "oops: pickle is readonly";
avi27b40072015-12-05 07:38:52 +0900398 size_t data_len = bits::Align(length, sizeof(uint32_t));
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900399 DCHECK_GE(data_len, length);
400#ifdef ARCH_CPU_64_BITS
avi27b40072015-12-05 07:38:52 +0900401 DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900402#endif
avi27b40072015-12-05 07:38:52 +0900403 DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900404 size_t new_size = write_offset_ + data_len;
405 if (new_size > capacity_after_header_) {
primiano47c69062015-07-25 05:13:32 +0900406 size_t new_capacity = capacity_after_header_ * 2;
407 const size_t kPickleHeapAlign = 4096;
408 if (new_capacity > kPickleHeapAlign)
409 new_capacity = bits::Align(new_capacity, kPickleHeapAlign) - kPayloadUnit;
410 Resize(std::max(new_capacity, new_size));
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900411 }
412
413 char* write = mutable_payload() + write_offset_;
rockot76180b02015-12-17 15:19:49 +0900414 memset(write + length, 0, data_len - length); // Always initialize padding
avi27b40072015-12-05 07:38:52 +0900415 header_->payload_size = static_cast<uint32_t>(new_size);
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900416 write_offset_ = new_size;
rockot76180b02015-12-17 15:19:49 +0900417 return write;
418}
419
420inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
421 DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
422 << "oops: pickle is readonly";
423 MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
424 void* write = ClaimUninitializedBytesInternal(length);
425 memcpy(write, data, length);
piman@chromium.org5d3eee22013-10-31 13:03:02 +0900426}
brettwd0d62652015-06-04 01:20:14 +0900427
428} // namespace base