ipc/chromium/src/base/pickle.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial