Home | History | Annotate | Download | only in base
      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 #include <limits>
     11 
     12 #include "base/bits.h"
     13 #include "base/macros.h"
     14 #include "build/build_config.h"
     15 
     16 namespace base {
     17 
     18 // static
     19 const int Pickle::kPayloadUnit = 64;
     20 
     21 static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
     22 
     23 PickleIterator::PickleIterator(const Pickle& pickle)
     24     : payload_(pickle.payload()),
     25       read_index_(0),
     26       end_index_(pickle.payload_size()) {
     27 }
     28 
     29 template <typename Type>
     30 inline bool PickleIterator::ReadBuiltinType(Type* result) {
     31   const char* read_from = GetReadPointerAndAdvance<Type>();
     32   if (!read_from)
     33     return false;
     34   if (sizeof(Type) > sizeof(uint32_t))
     35     memcpy(result, read_from, sizeof(*result));
     36   else
     37     *result = *reinterpret_cast<const Type*>(read_from);
     38   return true;
     39 }
     40 
     41 inline void PickleIterator::Advance(size_t size) {
     42   size_t aligned_size = bits::Align(size, sizeof(uint32_t));
     43   if (end_index_ - read_index_ < aligned_size) {
     44     read_index_ = end_index_;
     45   } else {
     46     read_index_ += aligned_size;
     47   }
     48 }
     49 
     50 template<typename Type>
     51 inline const char* PickleIterator::GetReadPointerAndAdvance() {
     52   if (sizeof(Type) > end_index_ - read_index_) {
     53     read_index_ = end_index_;
     54     return NULL;
     55   }
     56   const char* current_read_ptr = payload_ + read_index_;
     57   Advance(sizeof(Type));
     58   return current_read_ptr;
     59 }
     60 
     61 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
     62   if (num_bytes < 0 ||
     63       end_index_ - read_index_ < static_cast<size_t>(num_bytes)) {
     64     read_index_ = end_index_;
     65     return NULL;
     66   }
     67   const char* current_read_ptr = payload_ + read_index_;
     68   Advance(num_bytes);
     69   return current_read_ptr;
     70 }
     71 
     72 inline const char* PickleIterator::GetReadPointerAndAdvance(
     73     int num_elements,
     74     size_t size_element) {
     75   // Check for int32_t overflow.
     76   int64_t num_bytes = static_cast<int64_t>(num_elements) * size_element;
     77   int num_bytes32 = static_cast<int>(num_bytes);
     78   if (num_bytes != static_cast<int64_t>(num_bytes32))
     79     return NULL;
     80   return GetReadPointerAndAdvance(num_bytes32);
     81 }
     82 
     83 bool PickleIterator::ReadBool(bool* result) {
     84   return ReadBuiltinType(result);
     85 }
     86 
     87 bool PickleIterator::ReadInt(int* result) {
     88   return ReadBuiltinType(result);
     89 }
     90 
     91 bool PickleIterator::ReadLong(long* result) {
     92   return ReadBuiltinType(result);
     93 }
     94 
     95 bool PickleIterator::ReadUInt16(uint16_t* result) {
     96   return ReadBuiltinType(result);
     97 }
     98 
     99 bool PickleIterator::ReadUInt32(uint32_t* result) {
    100   return ReadBuiltinType(result);
    101 }
    102 
    103 bool PickleIterator::ReadInt64(int64_t* result) {
    104   return ReadBuiltinType(result);
    105 }
    106 
    107 bool PickleIterator::ReadUInt64(uint64_t* result) {
    108   return ReadBuiltinType(result);
    109 }
    110 
    111 bool 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.
    114   uint64_t result_uint64 = 0;
    115   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 
    121 bool PickleIterator::ReadFloat(float* result) {
    122   // 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;
    131 }
    132 
    133 bool 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 
    145 bool 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 
    157 bool PickleIterator::ReadStringPiece(StringPiece* result) {
    158   int len;
    159   if (!ReadInt(&len))
    160     return false;
    161   const char* read_from = GetReadPointerAndAdvance(len);
    162   if (!read_from)
    163     return false;
    164 
    165   *result = StringPiece(read_from, len);
    166   return true;
    167 }
    168 
    169 bool 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 
    181 bool PickleIterator::ReadStringPiece16(StringPiece16* result) {
    182   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 
    189   *result = StringPiece16(reinterpret_cast<const char16*>(read_from), len);
    190   return true;
    191 }
    192 
    193 bool 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 
    203 bool 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 
    211 // Payload is uint32_t aligned.
    212 
    213 Pickle::Pickle()
    214     : header_(NULL),
    215       header_size_(sizeof(Header)),
    216       capacity_after_header_(0),
    217       write_offset_(0) {
    218   static_assert((Pickle::kPayloadUnit & (Pickle::kPayloadUnit - 1)) == 0,
    219                 "Pickle::kPayloadUnit must be a power of two");
    220   Resize(kPayloadUnit);
    221   header_->payload_size = 0;
    222 }
    223 
    224 Pickle::Pickle(int header_size)
    225     : header_(NULL),
    226       header_size_(bits::Align(header_size, sizeof(uint32_t))),
    227       capacity_after_header_(0),
    228       write_offset_(0) {
    229   DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
    230   DCHECK_LE(header_size, kPayloadUnit);
    231   Resize(kPayloadUnit);
    232   header_->payload_size = 0;
    233 }
    234 
    235 Pickle::Pickle(const char* data, int data_len)
    236     : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
    237       header_size_(0),
    238       capacity_after_header_(kCapacityReadOnly),
    239       write_offset_(0) {
    240   if (data_len >= static_cast<int>(sizeof(Header)))
    241     header_size_ = data_len - header_->payload_size;
    242 
    243   if (header_size_ > static_cast<unsigned int>(data_len))
    244     header_size_ = 0;
    245 
    246   if (header_size_ != bits::Align(header_size_, sizeof(uint32_t)))
    247     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;
    252 }
    253 
    254 Pickle::Pickle(const Pickle& other)
    255     : header_(NULL),
    256       header_size_(other.header_size_),
    257       capacity_after_header_(0),
    258       write_offset_(other.write_offset_) {
    259   Resize(other.header_->payload_size);
    260   memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
    261 }
    262 
    263 Pickle::~Pickle() {
    264   if (capacity_after_header_ != kCapacityReadOnly)
    265     free(header_);
    266 }
    267 
    268 Pickle& Pickle::operator=(const Pickle& other) {
    269   if (this == &other) {
    270     NOTREACHED();
    271     return *this;
    272   }
    273   if (capacity_after_header_ == kCapacityReadOnly) {
    274     header_ = NULL;
    275     capacity_after_header_ = 0;
    276   }
    277   if (header_size_ != other.header_size_) {
    278     free(header_);
    279     header_ = NULL;
    280     header_size_ = other.header_size_;
    281   }
    282   Resize(other.header_->payload_size);
    283   memcpy(header_, other.header_,
    284          other.header_size_ + other.header_->payload_size);
    285   write_offset_ = other.write_offset_;
    286   return *this;
    287 }
    288 
    289 bool Pickle::WriteString(const StringPiece& value) {
    290   if (!WriteInt(static_cast<int>(value.size())))
    291     return false;
    292 
    293   return WriteBytes(value.data(), static_cast<int>(value.size()));
    294 }
    295 
    296 bool Pickle::WriteString16(const StringPiece16& value) {
    297   if (!WriteInt(static_cast<int>(value.size())))
    298     return false;
    299 
    300   return WriteBytes(value.data(),
    301                     static_cast<int>(value.size()) * sizeof(char16));
    302 }
    303 
    304 bool Pickle::WriteData(const char* data, int length) {
    305   return length >= 0 && WriteInt(length) && WriteBytes(data, length);
    306 }
    307 
    308 bool Pickle::WriteBytes(const void* data, int length) {
    309   WriteBytesCommon(data, length);
    310   return true;
    311 }
    312 
    313 void Pickle::Reserve(size_t length) {
    314   size_t data_len = bits::Align(length, sizeof(uint32_t));
    315   DCHECK_GE(data_len, length);
    316 #ifdef ARCH_CPU_64_BITS
    317   DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
    318 #endif
    319   DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
    320   size_t new_size = write_offset_ + data_len;
    321   if (new_size > capacity_after_header_)
    322     Resize(capacity_after_header_ * 2 + new_size);
    323 }
    324 
    325 void Pickle::Resize(size_t new_capacity) {
    326   CHECK_NE(capacity_after_header_, kCapacityReadOnly);
    327   capacity_after_header_ = bits::Align(new_capacity, kPayloadUnit);
    328   void* p = realloc(header_, GetTotalAllocatedSize());
    329   CHECK(p);
    330   header_ = reinterpret_cast<Header*>(p);
    331 }
    332 
    333 void* 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 
    340 size_t Pickle::GetTotalAllocatedSize() const {
    341   if (capacity_after_header_ == kCapacityReadOnly)
    342     return 0;
    343   return header_size_ + capacity_after_header_;
    344 }
    345 
    346 // static
    347 const char* Pickle::FindNext(size_t header_size,
    348                              const char* start,
    349                              const char* end) {
    350   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
    361 bool Pickle::PeekNext(size_t header_size,
    362                       const char* start,
    363                       const char* end,
    364                       size_t* pickle_size) {
    365   DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32_t)));
    366   DCHECK_GE(header_size, sizeof(Header));
    367   DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
    368 
    369   size_t length = static_cast<size_t>(end - start);
    370   if (length < sizeof(Header))
    371     return false;
    372 
    373   const Header* hdr = reinterpret_cast<const Header*>(start);
    374   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;
    385 }
    386 
    387 template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
    388   WriteBytesCommon(data, length);
    389 }
    390 
    391 template void Pickle::WriteBytesStatic<2>(const void* data);
    392 template void Pickle::WriteBytesStatic<4>(const void* data);
    393 template void Pickle::WriteBytesStatic<8>(const void* data);
    394 
    395 inline void* Pickle::ClaimUninitializedBytesInternal(size_t length) {
    396   DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
    397       << "oops: pickle is readonly";
    398   size_t data_len = bits::Align(length, sizeof(uint32_t));
    399   DCHECK_GE(data_len, length);
    400 #ifdef ARCH_CPU_64_BITS
    401   DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
    402 #endif
    403   DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
    404   size_t new_size = write_offset_ + data_len;
    405   if (new_size > capacity_after_header_) {
    406     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));
    411   }
    412 
    413   char* write = mutable_payload() + write_offset_;
    414   memset(write + length, 0, data_len - length);  // Always initialize padding
    415   header_->payload_size = static_cast<uint32_t>(new_size);
    416   write_offset_ = new_size;
    417   return write;
    418 }
    419 
    420 inline 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);
    426 }
    427 
    428 }  // namespace base
    429