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