Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // Copyright (c) 2006-2008 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.
5 #include "base/pickle.h"
7 #include "mozilla/Alignment.h"
8 #include "mozilla/Endian.h"
9 #include "mozilla/TypeTraits.h"
11 #include <stdlib.h>
13 #include <limits>
14 #include <string>
15 #include <algorithm>
17 #include "nsDebug.h"
19 //------------------------------------------------------------------------------
21 static_assert(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
22 "Insufficient alignment");
24 // static
25 const int Pickle::kPayloadUnit = 64;
27 // We mark a read only pickle with a special capacity_.
28 static const uint32_t kCapacityReadOnly = (uint32_t) -1;
30 static const char kBytePaddingMarker = char(0xbf);
32 namespace {
34 // We want to copy data to our payload as efficiently as possible.
35 // memcpy fits the bill for copying, but not all compilers or
36 // architectures support inlining memcpy from void*, which has unknown
37 // static alignment. However, we know that all the members of our
38 // payload will be aligned on memberAlignmentType boundaries. We
39 // therefore use that knowledge to construct a copier that will copy
40 // efficiently (via standard C++ assignment mechanisms) if the datatype
41 // needs that alignment or less, and memcpy otherwise. (The compiler
42 // may still inline memcpy, of course.)
44 template<typename T, size_t size, bool hasSufficientAlignment>
45 struct Copier
46 {
47 static void Copy(T* dest, void** iter) {
48 memcpy(dest, *iter, sizeof(T));
49 }
50 };
52 // Copying 64-bit quantities happens often enough and can easily be made
53 // worthwhile on 32-bit platforms, so handle it specially. Only do it
54 // if 64-bit types aren't sufficiently aligned; the alignment
55 // requirements for them vary between 32-bit platforms.
56 #ifndef HAVE_64BIT_OS
57 template<typename T>
58 struct Copier<T, sizeof(uint64_t), false>
59 {
60 static void Copy(T* dest, void** iter) {
61 #if MOZ_LITTLE_ENDIAN
62 static const int loIndex = 0, hiIndex = 1;
63 #else
64 static const int loIndex = 1, hiIndex = 0;
65 #endif
66 static_assert(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
67 "Pointers have different alignments");
68 uint32_t* src = *reinterpret_cast<uint32_t**>(iter);
69 uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
70 uint32dest[loIndex] = src[loIndex];
71 uint32dest[hiIndex] = src[hiIndex];
72 }
73 };
74 #endif
76 template<typename T, size_t size>
77 struct Copier<T, size, true>
78 {
79 static void Copy(T* dest, void** iter) {
80 // The reinterpret_cast is only safe if two conditions hold:
81 // (1) If the alignment of T* is the same as void*;
82 // (2) The alignment of the data in *iter is at least as
83 // big as MOZ_ALIGNOF(T).
84 // Check the first condition, as the second condition is already
85 // known to be true, or we wouldn't be here.
86 static_assert(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*),
87 "Pointers have different alignments");
88 *dest = *(*reinterpret_cast<T**>(iter));
89 }
90 };
92 template<typename T>
93 void CopyFromIter(T* dest, void** iter) {
94 static_assert(mozilla::IsPod<T>::value, "Copied type must be a POD type");
95 Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter);
96 }
98 } // anonymous namespace
100 // Payload is sizeof(Pickle::memberAlignmentType) aligned.
102 Pickle::Pickle()
103 : header_(NULL),
104 header_size_(sizeof(Header)),
105 capacity_(0),
106 variable_buffer_offset_(0) {
107 Resize(kPayloadUnit);
108 header_->payload_size = 0;
109 }
111 Pickle::Pickle(int header_size)
112 : header_(NULL),
113 header_size_(AlignInt(header_size)),
114 capacity_(0),
115 variable_buffer_offset_(0) {
116 DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
117 DCHECK(header_size <= kPayloadUnit);
118 Resize(kPayloadUnit);
119 if (!header_) {
120 NS_ABORT_OOM(kPayloadUnit);
121 }
122 header_->payload_size = 0;
123 }
125 Pickle::Pickle(const char* data, int data_len)
126 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
127 header_size_(data_len - header_->payload_size),
128 capacity_(kCapacityReadOnly),
129 variable_buffer_offset_(0) {
130 DCHECK(header_size_ >= sizeof(Header));
131 DCHECK(header_size_ == AlignInt(header_size_));
132 }
134 Pickle::Pickle(const Pickle& other)
135 : header_(NULL),
136 header_size_(other.header_size_),
137 capacity_(0),
138 variable_buffer_offset_(other.variable_buffer_offset_) {
139 uint32_t payload_size = header_size_ + other.header_->payload_size;
140 bool resized = Resize(payload_size);
141 if (!resized) {
142 NS_ABORT_OOM(payload_size);
143 }
144 memcpy(header_, other.header_, payload_size);
145 }
147 Pickle::~Pickle() {
148 if (capacity_ != kCapacityReadOnly)
149 free(header_);
150 }
152 Pickle& Pickle::operator=(const Pickle& other) {
153 if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
154 free(header_);
155 header_ = NULL;
156 header_size_ = other.header_size_;
157 }
158 bool resized = Resize(other.header_size_ + other.header_->payload_size);
159 if (!resized) {
160 NS_ABORT_OOM(other.header_size_ + other.header_->payload_size);
161 }
162 memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
163 variable_buffer_offset_ = other.variable_buffer_offset_;
164 return *this;
165 }
167 bool Pickle::ReadBool(void** iter, bool* result) const {
168 DCHECK(iter);
170 int tmp;
171 if (!ReadInt(iter, &tmp))
172 return false;
173 DCHECK(0 == tmp || 1 == tmp);
174 *result = tmp ? true : false;
175 return true;
176 }
178 bool Pickle::ReadInt16(void** iter, int16_t* result) const {
179 DCHECK(iter);
180 if (!*iter)
181 *iter = const_cast<char*>(payload());
183 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
184 return false;
186 CopyFromIter(result, iter);
188 UpdateIter(iter, sizeof(*result));
189 return true;
190 }
192 bool Pickle::ReadUInt16(void** iter, uint16_t* result) const {
193 DCHECK(iter);
194 if (!*iter)
195 *iter = const_cast<char*>(payload());
197 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
198 return false;
200 CopyFromIter(result, iter);
202 UpdateIter(iter, sizeof(*result));
203 return true;
204 }
206 bool Pickle::ReadInt(void** iter, int* result) const {
207 DCHECK(iter);
208 if (!*iter)
209 *iter = const_cast<char*>(payload());
211 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
212 return false;
214 CopyFromIter(result, iter);
216 UpdateIter(iter, sizeof(*result));
217 return true;
218 }
220 // Always written as a 64-bit value since the size for this type can
221 // differ between architectures.
222 bool Pickle::ReadLong(void** iter, long* result) const {
223 DCHECK(iter);
224 if (!*iter)
225 *iter = const_cast<char*>(payload());
227 int64_t bigResult = 0;
228 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
229 return false;
231 CopyFromIter(&bigResult, iter);
232 DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
233 *result = static_cast<long>(bigResult);
235 UpdateIter(iter, sizeof(bigResult));
236 return true;
237 }
239 // Always written as a 64-bit value since the size for this type can
240 // differ between architectures.
241 bool Pickle::ReadULong(void** iter, unsigned long* result) const {
242 DCHECK(iter);
243 if (!*iter)
244 *iter = const_cast<char*>(payload());
246 uint64_t bigResult = 0;
247 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
248 return false;
250 CopyFromIter(&bigResult, iter);
251 DCHECK(bigResult <= ULONG_MAX);
252 *result = static_cast<unsigned long>(bigResult);
254 UpdateIter(iter, sizeof(bigResult));
255 return true;
256 }
258 bool Pickle::ReadLength(void** iter, int* result) const {
259 if (!ReadInt(iter, result))
260 return false;
261 return ((*result) >= 0);
262 }
264 // Always written as a 64-bit value since the size for this type can
265 // differ between architectures.
266 bool Pickle::ReadSize(void** iter, size_t* result) const {
267 DCHECK(iter);
268 if (!*iter)
269 *iter = const_cast<char*>(payload());
271 uint64_t bigResult = 0;
272 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
273 return false;
275 CopyFromIter(&bigResult, iter);
276 DCHECK(bigResult <= std::numeric_limits<size_t>::max());
277 *result = static_cast<size_t>(bigResult);
279 UpdateIter(iter, sizeof(bigResult));
280 return true;
281 }
283 bool Pickle::ReadInt32(void** iter, int32_t* result) const {
284 DCHECK(iter);
285 if (!*iter)
286 *iter = const_cast<char*>(payload());
288 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
289 return false;
291 CopyFromIter(result, iter);
293 UpdateIter(iter, sizeof(*result));
294 return true;
295 }
297 bool Pickle::ReadUInt32(void** iter, uint32_t* result) const {
298 DCHECK(iter);
299 if (!*iter)
300 *iter = const_cast<char*>(payload());
302 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
303 return false;
305 CopyFromIter(result, iter);
307 UpdateIter(iter, sizeof(*result));
308 return true;
309 }
311 bool Pickle::ReadInt64(void** iter, int64_t* result) const {
312 DCHECK(iter);
313 if (!*iter)
314 *iter = const_cast<char*>(payload());
316 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
317 return false;
319 CopyFromIter(result, iter);
321 UpdateIter(iter, sizeof(*result));
322 return true;
323 }
325 bool Pickle::ReadUInt64(void** iter, uint64_t* result) const {
326 DCHECK(iter);
327 if (!*iter)
328 *iter = const_cast<char*>(payload());
330 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
331 return false;
333 CopyFromIter(result, iter);
335 UpdateIter(iter, sizeof(*result));
336 return true;
337 }
339 bool Pickle::ReadDouble(void** iter, double* result) const {
340 DCHECK(iter);
341 if (!*iter)
342 *iter = const_cast<char*>(payload());
344 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
345 return false;
347 CopyFromIter(result, iter);
349 UpdateIter(iter, sizeof(*result));
350 return true;
351 }
353 // Always written as a 64-bit value since the size for this type can
354 // differ between architectures.
355 bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
356 DCHECK(iter);
357 if (!*iter)
358 *iter = const_cast<char*>(payload());
360 int64_t bigResult = 0;
361 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
362 return false;
364 CopyFromIter(&bigResult, iter);
365 DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
366 *result = static_cast<intptr_t>(bigResult);
368 UpdateIter(iter, sizeof(bigResult));
369 return true;
370 }
372 bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const {
373 DCHECK(iter);
374 if (!*iter)
375 *iter = const_cast<char*>(payload());
377 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
378 return false;
380 CopyFromIter(result, iter);
382 UpdateIter(iter, sizeof(*result));
383 return true;
384 }
386 bool Pickle::ReadString(void** iter, std::string* result) const {
387 DCHECK(iter);
388 if (!*iter)
389 *iter = const_cast<char*>(payload());
391 int len;
392 if (!ReadLength(iter, &len))
393 return false;
394 if (!IteratorHasRoomFor(*iter, len))
395 return false;
397 char* chars = reinterpret_cast<char*>(*iter);
398 result->assign(chars, len);
400 UpdateIter(iter, len);
401 return true;
402 }
404 bool Pickle::ReadWString(void** iter, std::wstring* result) const {
405 DCHECK(iter);
406 if (!*iter)
407 *iter = const_cast<char*>(payload());
409 int len;
410 if (!ReadLength(iter, &len))
411 return false;
412 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
413 return false;
415 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
416 result->assign(chars, len);
418 UpdateIter(iter, len * sizeof(wchar_t));
419 return true;
420 }
422 bool Pickle::ReadString16(void** iter, string16* result) const {
423 DCHECK(iter);
424 if (!*iter)
425 *iter = const_cast<char*>(payload());
427 int len;
428 if (!ReadLength(iter, &len))
429 return false;
430 if (!IteratorHasRoomFor(*iter, len))
431 return false;
433 char16* chars = reinterpret_cast<char16*>(*iter);
434 result->assign(chars, len);
436 UpdateIter(iter, len * sizeof(char16));
437 return true;
438 }
440 bool Pickle::ReadBytes(void** iter, const char** data, int length,
441 uint32_t alignment) const {
442 DCHECK(iter);
443 DCHECK(data);
444 DCHECK(alignment == 4 || alignment == 8);
445 DCHECK(intptr_t(header_) % alignment == 0);
447 if (!*iter)
448 *iter = const_cast<char*>(payload());
450 uint32_t paddingLen = intptr_t(*iter) % alignment;
451 if (paddingLen) {
452 #ifdef DEBUG
453 {
454 const char* padding = static_cast<const char*>(*iter);
455 for (uint32_t i = 0; i < paddingLen; i++) {
456 DCHECK(*(padding + i) == kBytePaddingMarker);
457 }
458 }
459 #endif
460 length += paddingLen;
461 }
463 if (!IteratorHasRoomFor(*iter, length))
464 return false;
466 *data = static_cast<const char*>(*iter) + paddingLen;
467 DCHECK(intptr_t(*data) % alignment == 0);
469 UpdateIter(iter, length);
470 return true;
471 }
473 bool Pickle::ReadData(void** iter, const char** data, int* length) const {
474 DCHECK(iter);
475 DCHECK(data);
476 DCHECK(length);
477 if (!*iter)
478 *iter = const_cast<char*>(payload());
480 if (!ReadLength(iter, length))
481 return false;
483 return ReadBytes(iter, data, *length);
484 }
486 char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
487 DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!";
489 // write at an alignment-aligned offset from the beginning of the header
490 uint32_t offset = AlignInt(header_->payload_size);
491 uint32_t padding = (header_size_ + offset) % alignment;
492 uint32_t new_size = offset + padding + AlignInt(length);
493 uint32_t needed_size = header_size_ + new_size;
495 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
496 return NULL;
498 DCHECK(intptr_t(header_) % alignment == 0);
500 #ifdef ARCH_CPU_64_BITS
501 DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
502 #endif
504 char* buffer = payload() + offset;
506 if (padding) {
507 memset(buffer, kBytePaddingMarker, padding);
508 buffer += padding;
509 }
511 DCHECK(intptr_t(buffer) % alignment == 0);
513 header_->payload_size = new_size;
515 #ifdef MOZ_VALGRIND
516 // pad the trailing end as well, so that valgrind
517 // doesn't complain when we write the buffer
518 padding = AlignInt(length) - length;
519 if (padding) {
520 memset(buffer + length, kBytePaddingMarker, padding);
521 }
522 #endif
524 return buffer;
525 }
527 void Pickle::EndWrite(char* dest, int length) {
528 // Zero-pad to keep tools like purify from complaining about uninitialized
529 // memory.
530 if (length % sizeof(memberAlignmentType))
531 memset(dest + length, 0,
532 sizeof(memberAlignmentType) - (length % sizeof(memberAlignmentType)));
533 }
535 bool Pickle::WriteBytes(const void* data, int data_len, uint32_t alignment) {
536 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
537 DCHECK(alignment == 4 || alignment == 8);
538 DCHECK(intptr_t(header_) % alignment == 0);
540 char* dest = BeginWrite(data_len, alignment);
541 if (!dest)
542 return false;
544 memcpy(dest, data, data_len);
546 EndWrite(dest, data_len);
547 return true;
548 }
550 bool Pickle::WriteString(const std::string& value) {
551 if (!WriteInt(static_cast<int>(value.size())))
552 return false;
554 return WriteBytes(value.data(), static_cast<int>(value.size()));
555 }
557 bool Pickle::WriteWString(const std::wstring& value) {
558 if (!WriteInt(static_cast<int>(value.size())))
559 return false;
561 return WriteBytes(value.data(),
562 static_cast<int>(value.size() * sizeof(wchar_t)));
563 }
565 bool Pickle::WriteString16(const string16& value) {
566 if (!WriteInt(static_cast<int>(value.size())))
567 return false;
569 return WriteBytes(value.data(),
570 static_cast<int>(value.size()) * sizeof(char16));
571 }
573 bool Pickle::WriteData(const char* data, int length) {
574 return WriteInt(length) && WriteBytes(data, length);
575 }
577 char* Pickle::BeginWriteData(int length) {
578 DCHECK_EQ(variable_buffer_offset_, 0U) <<
579 "There can only be one variable buffer in a Pickle";
581 if (!WriteInt(length))
582 return NULL;
584 char *data_ptr = BeginWrite(length, sizeof(memberAlignmentType));
585 if (!data_ptr)
586 return NULL;
588 variable_buffer_offset_ =
589 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
591 // EndWrite doesn't necessarily have to be called after the write operation,
592 // so we call it here to pad out what the caller will eventually write.
593 EndWrite(data_ptr, length);
594 return data_ptr;
595 }
597 void Pickle::TrimWriteData(int new_length) {
598 DCHECK(variable_buffer_offset_ != 0);
600 // Fetch the the variable buffer size
601 int* cur_length = reinterpret_cast<int*>(
602 reinterpret_cast<char*>(header_) + variable_buffer_offset_);
604 if (new_length < 0 || new_length > *cur_length) {
605 NOTREACHED() << "Invalid length in TrimWriteData.";
606 return;
607 }
609 // Update the payload size and variable buffer size
610 header_->payload_size -= (*cur_length - new_length);
611 *cur_length = new_length;
612 }
614 bool Pickle::Resize(uint32_t new_capacity) {
615 new_capacity = ConstantAligner<kPayloadUnit>::align(new_capacity);
617 void* p = realloc(header_, new_capacity);
618 if (!p)
619 return false;
621 header_ = reinterpret_cast<Header*>(p);
622 capacity_ = new_capacity;
623 return true;
624 }
626 // static
627 const char* Pickle::FindNext(uint32_t header_size,
628 const char* start,
629 const char* end) {
630 DCHECK(header_size == AlignInt(header_size));
631 DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
633 const Header* hdr = reinterpret_cast<const Header*>(start);
634 const char* payload_base = start + header_size;
635 const char* payload_end = payload_base + hdr->payload_size;
636 if (payload_end < payload_base)
637 return NULL;
639 return (payload_end > end) ? NULL : payload_end;
640 }