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 13 using base::char16; 14 using base::string16; 15 16 // static 17 const int Pickle::kPayloadUnit = 64; 18 19 static const size_t kCapacityReadOnly = static_cast<size_t>(-1); 20 21 PickleIterator::PickleIterator(const Pickle& pickle) 22 : payload_(pickle.payload()), 23 read_index_(0), 24 end_index_(pickle.payload_size()) { 25 } 26 27 template <typename Type> 28 inline 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 39 inline 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 48 template<typename Type> 49 inline 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 59 const 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 70 inline 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 81 bool PickleIterator::ReadBool(bool* result) { 82 return ReadBuiltinType(result); 83 } 84 85 bool PickleIterator::ReadInt(int* result) { 86 return ReadBuiltinType(result); 87 } 88 89 bool PickleIterator::ReadLong(long* result) { 90 return ReadBuiltinType(result); 91 } 92 93 bool PickleIterator::ReadUInt16(uint16* result) { 94 return ReadBuiltinType(result); 95 } 96 97 bool PickleIterator::ReadUInt32(uint32* result) { 98 return ReadBuiltinType(result); 99 } 100 101 bool PickleIterator::ReadInt64(int64* result) { 102 return ReadBuiltinType(result); 103 } 104 105 bool PickleIterator::ReadUInt64(uint64* result) { 106 return ReadBuiltinType(result); 107 } 108 109 bool 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 121 bool 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 133 bool 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 145 bool 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 157 bool 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 169 bool 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 179 bool 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 189 Pickle::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 198 Pickle::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 209 Pickle::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 228 Pickle::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 238 Pickle::~Pickle() { 239 if (capacity_after_header_ != kCapacityReadOnly) 240 free(header_); 241 } 242 243 Pickle& 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 264 bool 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 271 bool 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 279 bool 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 287 bool Pickle::WriteData(const char* data, int length) { 288 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 289 } 290 291 bool Pickle::WriteBytes(const void* data, int length) { 292 WriteBytesCommon(data, length); 293 return true; 294 } 295 296 void 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 308 void 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 319 const 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 335 template <size_t length> void Pickle::WriteBytesStatic(const void* data) { 336 WriteBytesCommon(data, length); 337 } 338 339 template void Pickle::WriteBytesStatic<2>(const void* data); 340 template void Pickle::WriteBytesStatic<4>(const void* data); 341 template void Pickle::WriteBytesStatic<8>(const void* data); 342 343 inline 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