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::ReadString(std::string* result) { 122 int len; 123 if (!ReadInt(&len)) 124 return false; 125 const char* read_from = GetReadPointerAndAdvance(len); 126 if (!read_from) 127 return false; 128 129 result->assign(read_from, len); 130 return true; 131 } 132 133 bool PickleIterator::ReadWString(std::wstring* result) { 134 int len; 135 if (!ReadInt(&len)) 136 return false; 137 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t)); 138 if (!read_from) 139 return false; 140 141 result->assign(reinterpret_cast<const wchar_t*>(read_from), len); 142 return true; 143 } 144 145 bool PickleIterator::ReadString16(string16* result) { 146 int len; 147 if (!ReadInt(&len)) 148 return false; 149 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16)); 150 if (!read_from) 151 return false; 152 153 result->assign(reinterpret_cast<const char16*>(read_from), len); 154 return true; 155 } 156 157 bool PickleIterator::ReadData(const char** data, int* length) { 158 *length = 0; 159 *data = 0; 160 161 if (!ReadInt(length)) 162 return false; 163 164 return ReadBytes(data, *length); 165 } 166 167 bool PickleIterator::ReadBytes(const char** data, int length) { 168 const char* read_from = GetReadPointerAndAdvance(length); 169 if (!read_from) 170 return false; 171 *data = read_from; 172 return true; 173 } 174 175 // Payload is uint32 aligned. 176 177 Pickle::Pickle() 178 : header_(NULL), 179 header_size_(sizeof(Header)), 180 capacity_after_header_(0), 181 write_offset_(0) { 182 Resize(kPayloadUnit); 183 header_->payload_size = 0; 184 } 185 186 Pickle::Pickle(int header_size) 187 : header_(NULL), 188 header_size_(AlignInt(header_size, sizeof(uint32))), 189 capacity_after_header_(0), 190 write_offset_(0) { 191 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header)); 192 DCHECK_LE(header_size, kPayloadUnit); 193 Resize(kPayloadUnit); 194 header_->payload_size = 0; 195 } 196 197 Pickle::Pickle(const char* data, int data_len) 198 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), 199 header_size_(0), 200 capacity_after_header_(kCapacityReadOnly), 201 write_offset_(0) { 202 if (data_len >= static_cast<int>(sizeof(Header))) 203 header_size_ = data_len - header_->payload_size; 204 205 if (header_size_ > static_cast<unsigned int>(data_len)) 206 header_size_ = 0; 207 208 if (header_size_ != AlignInt(header_size_, sizeof(uint32))) 209 header_size_ = 0; 210 211 // If there is anything wrong with the data, we're not going to use it. 212 if (!header_size_) 213 header_ = NULL; 214 } 215 216 Pickle::Pickle(const Pickle& other) 217 : header_(NULL), 218 header_size_(other.header_size_), 219 capacity_after_header_(0), 220 write_offset_(other.write_offset_) { 221 size_t payload_size = header_size_ + other.header_->payload_size; 222 Resize(payload_size); 223 memcpy(header_, other.header_, payload_size); 224 } 225 226 Pickle::~Pickle() { 227 if (capacity_after_header_ != kCapacityReadOnly) 228 free(header_); 229 } 230 231 Pickle& Pickle::operator=(const Pickle& other) { 232 if (this == &other) { 233 NOTREACHED(); 234 return *this; 235 } 236 if (capacity_after_header_ == kCapacityReadOnly) { 237 header_ = NULL; 238 capacity_after_header_ = 0; 239 } 240 if (header_size_ != other.header_size_) { 241 free(header_); 242 header_ = NULL; 243 header_size_ = other.header_size_; 244 } 245 Resize(other.header_->payload_size); 246 memcpy(header_, other.header_, 247 other.header_size_ + other.header_->payload_size); 248 write_offset_ = other.write_offset_; 249 return *this; 250 } 251 252 bool Pickle::WriteString(const std::string& value) { 253 if (!WriteInt(static_cast<int>(value.size()))) 254 return false; 255 256 return WriteBytes(value.data(), static_cast<int>(value.size())); 257 } 258 259 bool Pickle::WriteWString(const std::wstring& value) { 260 if (!WriteInt(static_cast<int>(value.size()))) 261 return false; 262 263 return WriteBytes(value.data(), 264 static_cast<int>(value.size() * sizeof(wchar_t))); 265 } 266 267 bool Pickle::WriteString16(const string16& value) { 268 if (!WriteInt(static_cast<int>(value.size()))) 269 return false; 270 271 return WriteBytes(value.data(), 272 static_cast<int>(value.size()) * sizeof(char16)); 273 } 274 275 bool Pickle::WriteData(const char* data, int length) { 276 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 277 } 278 279 bool Pickle::WriteBytes(const void* data, int length) { 280 WriteBytesCommon(data, length); 281 return true; 282 } 283 284 void Pickle::Reserve(size_t length) { 285 size_t data_len = AlignInt(length, sizeof(uint32)); 286 DCHECK_GE(data_len, length); 287 #ifdef ARCH_CPU_64_BITS 288 DCHECK_LE(data_len, kuint32max); 289 #endif 290 DCHECK_LE(write_offset_, kuint32max - data_len); 291 size_t new_size = write_offset_ + data_len; 292 if (new_size > capacity_after_header_) 293 Resize(capacity_after_header_ * 2 + new_size); 294 } 295 296 void Pickle::Resize(size_t new_capacity) { 297 new_capacity = AlignInt(new_capacity, kPayloadUnit); 298 299 CHECK_NE(capacity_after_header_, kCapacityReadOnly); 300 void* p = realloc(header_, header_size_ + new_capacity); 301 CHECK(p); 302 header_ = reinterpret_cast<Header*>(p); 303 capacity_after_header_ = new_capacity; 304 } 305 306 // static 307 const char* Pickle::FindNext(size_t header_size, 308 const char* start, 309 const char* end) { 310 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32))); 311 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit)); 312 313 size_t length = static_cast<size_t>(end - start); 314 if (length < sizeof(Header)) 315 return NULL; 316 317 const Header* hdr = reinterpret_cast<const Header*>(start); 318 if (length < header_size || length - header_size < hdr->payload_size) 319 return NULL; 320 return start + header_size + hdr->payload_size; 321 } 322 323 template <size_t length> void Pickle::WriteBytesStatic(const void* data) { 324 WriteBytesCommon(data, length); 325 } 326 327 template void Pickle::WriteBytesStatic<2>(const void* data); 328 template void Pickle::WriteBytesStatic<4>(const void* data); 329 template void Pickle::WriteBytesStatic<8>(const void* data); 330 331 inline void Pickle::WriteBytesCommon(const void* data, size_t length) { 332 DCHECK_NE(kCapacityReadOnly, capacity_after_header_) 333 << "oops: pickle is readonly"; 334 size_t data_len = AlignInt(length, sizeof(uint32)); 335 DCHECK_GE(data_len, length); 336 #ifdef ARCH_CPU_64_BITS 337 DCHECK_LE(data_len, kuint32max); 338 #endif 339 DCHECK_LE(write_offset_, kuint32max - data_len); 340 size_t new_size = write_offset_ + data_len; 341 if (new_size > capacity_after_header_) { 342 Resize(std::max(capacity_after_header_ * 2, new_size)); 343 } 344 345 char* write = mutable_payload() + write_offset_; 346 memcpy(write, data, length); 347 memset(write + length, 0, data_len - length); 348 header_->payload_size = static_cast<uint32>(new_size); 349 write_offset_ = new_size; 350 } 351