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 <limits.h> 6#include <stddef.h> 7#include <stdint.h> 8 9#include <string> 10 11#include "base/macros.h" 12#include "base/memory/scoped_ptr.h" 13#include "base/pickle.h" 14#include "base/strings/string16.h" 15#include "base/strings/utf_string_conversions.h" 16#include "testing/gtest/include/gtest/gtest.h" 17 18namespace base { 19 20namespace { 21 22const bool testbool1 = false; 23const bool testbool2 = true; 24const int testint = 2093847192; 25const long testlong = 1093847192; 26const uint16_t testuint16 = 32123; 27const uint32_t testuint32 = 1593847192; 28const int64_t testint64 = -0x7E8CA9253104BDFCLL; 29const uint64_t testuint64 = 0xCE8CA9253104BDF7ULL; 30const size_t testsizet = 0xFEDC7654; 31const float testfloat = 3.1415926935f; 32const double testdouble = 2.71828182845904523; 33const std::string teststring("Hello world"); // note non-aligned string length 34const std::wstring testwstring(L"Hello, world"); 35const string16 teststring16(ASCIIToUTF16("Hello, world")); 36const char testrawstring[] = "Hello new world"; // Test raw string writing 37// Test raw char16 writing, assumes UTF16 encoding is ANSI for alpha chars. 38const char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0}; 39const char testdata[] = "AAA\0BBB\0"; 40const int testdatalen = arraysize(testdata) - 1; 41 42// checks that the results can be read correctly from the Pickle 43void VerifyResult(const Pickle& pickle) { 44 PickleIterator iter(pickle); 45 46 bool outbool; 47 EXPECT_TRUE(iter.ReadBool(&outbool)); 48 EXPECT_FALSE(outbool); 49 EXPECT_TRUE(iter.ReadBool(&outbool)); 50 EXPECT_TRUE(outbool); 51 52 int outint; 53 EXPECT_TRUE(iter.ReadInt(&outint)); 54 EXPECT_EQ(testint, outint); 55 56 long outlong; 57 EXPECT_TRUE(iter.ReadLong(&outlong)); 58 EXPECT_EQ(testlong, outlong); 59 60 uint16_t outuint16; 61 EXPECT_TRUE(iter.ReadUInt16(&outuint16)); 62 EXPECT_EQ(testuint16, outuint16); 63 64 uint32_t outuint32; 65 EXPECT_TRUE(iter.ReadUInt32(&outuint32)); 66 EXPECT_EQ(testuint32, outuint32); 67 68 int64_t outint64; 69 EXPECT_TRUE(iter.ReadInt64(&outint64)); 70 EXPECT_EQ(testint64, outint64); 71 72 uint64_t outuint64; 73 EXPECT_TRUE(iter.ReadUInt64(&outuint64)); 74 EXPECT_EQ(testuint64, outuint64); 75 76 size_t outsizet; 77 EXPECT_TRUE(iter.ReadSizeT(&outsizet)); 78 EXPECT_EQ(testsizet, outsizet); 79 80 float outfloat; 81 EXPECT_TRUE(iter.ReadFloat(&outfloat)); 82 EXPECT_EQ(testfloat, outfloat); 83 84 double outdouble; 85 EXPECT_TRUE(iter.ReadDouble(&outdouble)); 86 EXPECT_EQ(testdouble, outdouble); 87 88 std::string outstring; 89 EXPECT_TRUE(iter.ReadString(&outstring)); 90 EXPECT_EQ(teststring, outstring); 91 92 string16 outstring16; 93 EXPECT_TRUE(iter.ReadString16(&outstring16)); 94 EXPECT_EQ(teststring16, outstring16); 95 96 StringPiece outstringpiece; 97 EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece)); 98 EXPECT_EQ(testrawstring, outstringpiece); 99 100 StringPiece16 outstringpiece16; 101 EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16)); 102 EXPECT_EQ(testrawstring16, outstringpiece16); 103 104 const char* outdata; 105 int outdatalen; 106 EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen)); 107 EXPECT_EQ(testdatalen, outdatalen); 108 EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); 109 110 // reads past the end should fail 111 EXPECT_FALSE(iter.ReadInt(&outint)); 112} 113 114} // namespace 115 116TEST(PickleTest, EncodeDecode) { 117 Pickle pickle; 118 119 EXPECT_TRUE(pickle.WriteBool(testbool1)); 120 EXPECT_TRUE(pickle.WriteBool(testbool2)); 121 EXPECT_TRUE(pickle.WriteInt(testint)); 122 EXPECT_TRUE( 123 pickle.WriteLongUsingDangerousNonPortableLessPersistableForm(testlong)); 124 EXPECT_TRUE(pickle.WriteUInt16(testuint16)); 125 EXPECT_TRUE(pickle.WriteUInt32(testuint32)); 126 EXPECT_TRUE(pickle.WriteInt64(testint64)); 127 EXPECT_TRUE(pickle.WriteUInt64(testuint64)); 128 EXPECT_TRUE(pickle.WriteSizeT(testsizet)); 129 EXPECT_TRUE(pickle.WriteFloat(testfloat)); 130 EXPECT_TRUE(pickle.WriteDouble(testdouble)); 131 EXPECT_TRUE(pickle.WriteString(teststring)); 132 EXPECT_TRUE(pickle.WriteString16(teststring16)); 133 EXPECT_TRUE(pickle.WriteString(testrawstring)); 134 EXPECT_TRUE(pickle.WriteString16(testrawstring16)); 135 EXPECT_TRUE(pickle.WriteData(testdata, testdatalen)); 136 VerifyResult(pickle); 137 138 // test copy constructor 139 Pickle pickle2(pickle); 140 VerifyResult(pickle2); 141 142 // test operator= 143 Pickle pickle3; 144 pickle3 = pickle; 145 VerifyResult(pickle3); 146} 147 148// Tests that reading/writing a size_t works correctly when the source process 149// is 64-bit. We rely on having both 32- and 64-bit trybots to validate both 150// arms of the conditional in this test. 151TEST(PickleTest, SizeTFrom64Bit) { 152 Pickle pickle; 153 // Under the hood size_t is always written as a 64-bit value, so simulate a 154 // 64-bit size_t even on 32-bit architectures by explicitly writing a 155 // uint64_t. 156 EXPECT_TRUE(pickle.WriteUInt64(testuint64)); 157 158 PickleIterator iter(pickle); 159 size_t outsizet; 160 if (sizeof(size_t) < sizeof(uint64_t)) { 161 // ReadSizeT() should return false when the original written value can't be 162 // represented as a size_t. 163 EXPECT_FALSE(iter.ReadSizeT(&outsizet)); 164 } else { 165 EXPECT_TRUE(iter.ReadSizeT(&outsizet)); 166 EXPECT_EQ(testuint64, outsizet); 167 } 168} 169 170// Tests that we can handle really small buffers. 171TEST(PickleTest, SmallBuffer) { 172 scoped_ptr<char[]> buffer(new char[1]); 173 174 // We should not touch the buffer. 175 Pickle pickle(buffer.get(), 1); 176 177 PickleIterator iter(pickle); 178 int data; 179 EXPECT_FALSE(iter.ReadInt(&data)); 180} 181 182// Tests that we can handle improper headers. 183TEST(PickleTest, BigSize) { 184 int buffer[] = { 0x56035200, 25, 40, 50 }; 185 186 Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer)); 187 188 PickleIterator iter(pickle); 189 int data; 190 EXPECT_FALSE(iter.ReadInt(&data)); 191} 192 193TEST(PickleTest, UnalignedSize) { 194 int buffer[] = { 10, 25, 40, 50 }; 195 196 Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer)); 197 198 PickleIterator iter(pickle); 199 int data; 200 EXPECT_FALSE(iter.ReadInt(&data)); 201} 202 203TEST(PickleTest, ZeroLenStr) { 204 Pickle pickle; 205 EXPECT_TRUE(pickle.WriteString(std::string())); 206 207 PickleIterator iter(pickle); 208 std::string outstr; 209 EXPECT_TRUE(iter.ReadString(&outstr)); 210 EXPECT_EQ("", outstr); 211} 212 213TEST(PickleTest, ZeroLenStr16) { 214 Pickle pickle; 215 EXPECT_TRUE(pickle.WriteString16(string16())); 216 217 PickleIterator iter(pickle); 218 std::string outstr; 219 EXPECT_TRUE(iter.ReadString(&outstr)); 220 EXPECT_EQ("", outstr); 221} 222 223TEST(PickleTest, BadLenStr) { 224 Pickle pickle; 225 EXPECT_TRUE(pickle.WriteInt(-2)); 226 227 PickleIterator iter(pickle); 228 std::string outstr; 229 EXPECT_FALSE(iter.ReadString(&outstr)); 230} 231 232TEST(PickleTest, BadLenStr16) { 233 Pickle pickle; 234 EXPECT_TRUE(pickle.WriteInt(-1)); 235 236 PickleIterator iter(pickle); 237 string16 outstr; 238 EXPECT_FALSE(iter.ReadString16(&outstr)); 239} 240 241TEST(PickleTest, PeekNext) { 242 struct CustomHeader : base::Pickle::Header { 243 int cookies[10]; 244 }; 245 246 Pickle pickle(sizeof(CustomHeader)); 247 248 EXPECT_TRUE(pickle.WriteString("Goooooooooooogle")); 249 250 const char* pickle_data = static_cast<const char*>(pickle.data()); 251 252 size_t pickle_size; 253 254 // Data range doesn't contain header 255 EXPECT_FALSE(Pickle::PeekNext( 256 sizeof(CustomHeader), 257 pickle_data, 258 pickle_data + sizeof(CustomHeader) - 1, 259 &pickle_size)); 260 261 // Data range contains header 262 EXPECT_TRUE(Pickle::PeekNext( 263 sizeof(CustomHeader), 264 pickle_data, 265 pickle_data + sizeof(CustomHeader), 266 &pickle_size)); 267 EXPECT_EQ(pickle_size, pickle.size()); 268 269 // Data range contains header and some other data 270 EXPECT_TRUE(Pickle::PeekNext( 271 sizeof(CustomHeader), 272 pickle_data, 273 pickle_data + sizeof(CustomHeader) + 1, 274 &pickle_size)); 275 EXPECT_EQ(pickle_size, pickle.size()); 276 277 // Data range contains full pickle 278 EXPECT_TRUE(Pickle::PeekNext( 279 sizeof(CustomHeader), 280 pickle_data, 281 pickle_data + pickle.size(), 282 &pickle_size)); 283 EXPECT_EQ(pickle_size, pickle.size()); 284} 285 286TEST(PickleTest, PeekNextOverflow) { 287 struct CustomHeader : base::Pickle::Header { 288 int cookies[10]; 289 }; 290 291 CustomHeader header; 292 293 // Check if we can wrap around at all 294 if (sizeof(size_t) > sizeof(header.payload_size)) 295 return; 296 297 const char* pickle_data = reinterpret_cast<const char*>(&header); 298 299 size_t pickle_size; 300 301 // Wrapping around is detected and reported as maximum size_t value 302 header.payload_size = static_cast<uint32_t>( 303 1 - static_cast<int32_t>(sizeof(CustomHeader))); 304 EXPECT_TRUE(Pickle::PeekNext( 305 sizeof(CustomHeader), 306 pickle_data, 307 pickle_data + sizeof(CustomHeader), 308 &pickle_size)); 309 EXPECT_EQ(pickle_size, std::numeric_limits<size_t>::max()); 310 311 // Ridiculous pickle sizes are fine (callers are supposed to 312 // verify them) 313 header.payload_size = 314 std::numeric_limits<uint32_t>::max() / 2 - sizeof(CustomHeader); 315 EXPECT_TRUE(Pickle::PeekNext( 316 sizeof(CustomHeader), 317 pickle_data, 318 pickle_data + sizeof(CustomHeader), 319 &pickle_size)); 320 EXPECT_EQ(pickle_size, std::numeric_limits<uint32_t>::max() / 2); 321} 322 323TEST(PickleTest, FindNext) { 324 Pickle pickle; 325 EXPECT_TRUE(pickle.WriteInt(1)); 326 EXPECT_TRUE(pickle.WriteString("Domo")); 327 328 const char* start = reinterpret_cast<const char*>(pickle.data()); 329 const char* end = start + pickle.size(); 330 331 EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end)); 332 EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1)); 333 EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1)); 334} 335 336TEST(PickleTest, FindNextWithIncompleteHeader) { 337 size_t header_size = sizeof(Pickle::Header); 338 scoped_ptr<char[]> buffer(new char[header_size - 1]); 339 memset(buffer.get(), 0x1, header_size - 1); 340 341 const char* start = buffer.get(); 342 const char* end = start + header_size - 1; 343 344 EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end)); 345} 346 347#if defined(COMPILER_MSVC) 348#pragma warning(push) 349#pragma warning(disable: 4146) 350#endif 351TEST(PickleTest, FindNextOverflow) { 352 size_t header_size = sizeof(Pickle::Header); 353 size_t header_size2 = 2 * header_size; 354 size_t payload_received = 100; 355 scoped_ptr<char[]> buffer(new char[header_size2 + payload_received]); 356 const char* start = buffer.get(); 357 Pickle::Header* header = reinterpret_cast<Pickle::Header*>(buffer.get()); 358 const char* end = start + header_size2 + payload_received; 359 // It is impossible to construct an overflow test otherwise. 360 if (sizeof(size_t) > sizeof(header->payload_size) || 361 sizeof(uintptr_t) > sizeof(header->payload_size)) 362 return; 363 364 header->payload_size = -(reinterpret_cast<uintptr_t>(start) + header_size2); 365 EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end)); 366 367 header->payload_size = -header_size2; 368 EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end)); 369 370 header->payload_size = 0; 371 end = start + header_size; 372 EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end)); 373} 374#if defined(COMPILER_MSVC) 375#pragma warning(pop) 376#endif 377 378TEST(PickleTest, GetReadPointerAndAdvance) { 379 Pickle pickle; 380 381 PickleIterator iter(pickle); 382 EXPECT_FALSE(iter.GetReadPointerAndAdvance(1)); 383 384 EXPECT_TRUE(pickle.WriteInt(1)); 385 EXPECT_TRUE(pickle.WriteInt(2)); 386 int bytes = sizeof(int) * 2; 387 388 EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0)); 389 EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1)); 390 EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1)); 391 EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes)); 392 EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1)); 393 EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX)); 394 EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN)); 395} 396 397TEST(PickleTest, Resize) { 398 size_t unit = Pickle::kPayloadUnit; 399 scoped_ptr<char[]> data(new char[unit]); 400 char* data_ptr = data.get(); 401 for (size_t i = 0; i < unit; i++) 402 data_ptr[i] = 'G'; 403 404 // construct a message that will be exactly the size of one payload unit, 405 // note that any data will have a 4-byte header indicating the size 406 const size_t payload_size_after_header = unit - sizeof(uint32_t); 407 Pickle pickle; 408 pickle.WriteData( 409 data_ptr, static_cast<int>(payload_size_after_header - sizeof(uint32_t))); 410 size_t cur_payload = payload_size_after_header; 411 412 // note: we assume 'unit' is a power of 2 413 EXPECT_EQ(unit, pickle.capacity_after_header()); 414 EXPECT_EQ(pickle.payload_size(), payload_size_after_header); 415 416 // fill out a full page (noting data header) 417 pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32_t))); 418 cur_payload += unit; 419 EXPECT_EQ(unit * 2, pickle.capacity_after_header()); 420 EXPECT_EQ(cur_payload, pickle.payload_size()); 421 422 // one more byte should double the capacity 423 pickle.WriteData(data_ptr, 1); 424 cur_payload += 8; 425 EXPECT_EQ(unit * 4, pickle.capacity_after_header()); 426 EXPECT_EQ(cur_payload, pickle.payload_size()); 427} 428 429namespace { 430 431struct CustomHeader : Pickle::Header { 432 int blah; 433}; 434 435} // namespace 436 437TEST(PickleTest, HeaderPadding) { 438 const uint32_t kMagic = 0x12345678; 439 440 Pickle pickle(sizeof(CustomHeader)); 441 pickle.WriteInt(kMagic); 442 443 // this should not overwrite the 'int' payload 444 pickle.headerT<CustomHeader>()->blah = 10; 445 446 PickleIterator iter(pickle); 447 int result; 448 ASSERT_TRUE(iter.ReadInt(&result)); 449 450 EXPECT_EQ(static_cast<uint32_t>(result), kMagic); 451} 452 453TEST(PickleTest, EqualsOperator) { 454 Pickle source; 455 source.WriteInt(1); 456 457 Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()), 458 source.size()); 459 Pickle copy; 460 copy = copy_refs_source_buffer; 461 ASSERT_EQ(source.size(), copy.size()); 462} 463 464TEST(PickleTest, EvilLengths) { 465 Pickle source; 466 std::string str(100000, 'A'); 467 EXPECT_TRUE(source.WriteData(str.c_str(), 100000)); 468 // ReadString16 used to have its read buffer length calculation wrong leading 469 // to out-of-bounds reading. 470 PickleIterator iter(source); 471 string16 str16; 472 EXPECT_FALSE(iter.ReadString16(&str16)); 473 474 // And check we didn't break ReadString16. 475 str16 = (wchar_t) 'A'; 476 Pickle str16_pickle; 477 EXPECT_TRUE(str16_pickle.WriteString16(str16)); 478 iter = PickleIterator(str16_pickle); 479 EXPECT_TRUE(iter.ReadString16(&str16)); 480 EXPECT_EQ(1U, str16.length()); 481 482 // Check we don't fail in a length check with invalid String16 size. 483 // (1<<31) * sizeof(char16) == 0, so this is particularly evil. 484 Pickle bad_len; 485 EXPECT_TRUE(bad_len.WriteInt(1 << 31)); 486 iter = PickleIterator(bad_len); 487 EXPECT_FALSE(iter.ReadString16(&str16)); 488} 489 490// Check we can write zero bytes of data and 'data' can be NULL. 491TEST(PickleTest, ZeroLength) { 492 Pickle pickle; 493 EXPECT_TRUE(pickle.WriteData(NULL, 0)); 494 495 PickleIterator iter(pickle); 496 const char* outdata; 497 int outdatalen; 498 EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen)); 499 EXPECT_EQ(0, outdatalen); 500 // We can't assert that outdata is NULL. 501} 502 503// Check that ReadBytes works properly with an iterator initialized to NULL. 504TEST(PickleTest, ReadBytes) { 505 Pickle pickle; 506 int data = 0x7abcd; 507 EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data))); 508 509 PickleIterator iter(pickle); 510 const char* outdata_char = NULL; 511 EXPECT_TRUE(iter.ReadBytes(&outdata_char, sizeof(data))); 512 513 int outdata; 514 memcpy(&outdata, outdata_char, sizeof(outdata)); 515 EXPECT_EQ(data, outdata); 516} 517 518// Checks that when a pickle is deep-copied, the result is not larger than 519// needed. 520TEST(PickleTest, DeepCopyResize) { 521 Pickle pickle; 522 while (pickle.capacity_after_header() != pickle.payload_size()) 523 pickle.WriteBool(true); 524 525 // Make a deep copy. 526 Pickle pickle2(pickle); 527 528 // Check that there isn't any extraneous capacity. 529 EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header()); 530} 531 532namespace { 533 534// Publicly exposes the ClaimBytes interface for testing. 535class TestingPickle : public Pickle { 536 public: 537 TestingPickle() {} 538 539 void* ClaimBytes(size_t num_bytes) { return Pickle::ClaimBytes(num_bytes); } 540}; 541 542} // namespace 543 544// Checks that claimed bytes are zero-initialized. 545TEST(PickleTest, ClaimBytesInitialization) { 546 static const int kChunkSize = 64; 547 TestingPickle pickle; 548 const char* bytes = static_cast<const char*>(pickle.ClaimBytes(kChunkSize)); 549 for (size_t i = 0; i < kChunkSize; ++i) { 550 EXPECT_EQ(0, bytes[i]); 551 } 552} 553 554// Checks that ClaimBytes properly advances the write offset. 555TEST(PickleTest, ClaimBytes) { 556 std::string data("Hello, world!"); 557 558 TestingPickle pickle; 559 pickle.WriteSizeT(data.size()); 560 void* bytes = pickle.ClaimBytes(data.size()); 561 pickle.WriteInt(42); 562 memcpy(bytes, data.data(), data.size()); 563 564 PickleIterator iter(pickle); 565 size_t out_data_length; 566 EXPECT_TRUE(iter.ReadSizeT(&out_data_length)); 567 EXPECT_EQ(data.size(), out_data_length); 568 569 const char* out_data = nullptr; 570 EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length)); 571 EXPECT_EQ(data, std::string(out_data, out_data_length)); 572 573 int out_value; 574 EXPECT_TRUE(iter.ReadInt(&out_value)); 575 EXPECT_EQ(42, out_value); 576} 577 578} // namespace base 579