// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/pickle.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" // Remove when this file is in the base namespace. using base::string16; namespace { const bool testbool1 = false; const bool testbool2 = true; const int testint = 2093847192; const long testlong = 1093847192; const uint16 testuint16 = 32123; const uint32 testuint32 = 1593847192; const int64 testint64 = -0x7E8CA9253104BDFCLL; const uint64 testuint64 = 0xCE8CA9253104BDF7ULL; const size_t testsizet = 0xFEDC7654; const float testfloat = 3.1415926935f; const double testdouble = 2.71828182845904523; const std::string teststring("Hello world"); // note non-aligned string length const std::wstring testwstring(L"Hello, world"); const base::string16 teststring16(base::ASCIIToUTF16("Hello, world")); const char testdata[] = "AAA\0BBB\0"; const int testdatalen = arraysize(testdata) - 1; // checks that the result void VerifyResult(const Pickle& pickle) { PickleIterator iter(pickle); bool outbool; EXPECT_TRUE(iter.ReadBool(&outbool)); EXPECT_FALSE(outbool); EXPECT_TRUE(iter.ReadBool(&outbool)); EXPECT_TRUE(outbool); int outint; EXPECT_TRUE(iter.ReadInt(&outint)); EXPECT_EQ(testint, outint); long outlong; EXPECT_TRUE(iter.ReadLong(&outlong)); EXPECT_EQ(testlong, outlong); uint16 outuint16; EXPECT_TRUE(iter.ReadUInt16(&outuint16)); EXPECT_EQ(testuint16, outuint16); uint32 outuint32; EXPECT_TRUE(iter.ReadUInt32(&outuint32)); EXPECT_EQ(testuint32, outuint32); int64 outint64; EXPECT_TRUE(iter.ReadInt64(&outint64)); EXPECT_EQ(testint64, outint64); uint64 outuint64; EXPECT_TRUE(iter.ReadUInt64(&outuint64)); EXPECT_EQ(testuint64, outuint64); size_t outsizet; EXPECT_TRUE(iter.ReadSizeT(&outsizet)); EXPECT_EQ(testsizet, outsizet); float outfloat; EXPECT_TRUE(iter.ReadFloat(&outfloat)); EXPECT_EQ(testfloat, outfloat); double outdouble; EXPECT_TRUE(iter.ReadDouble(&outdouble)); EXPECT_EQ(testdouble, outdouble); std::string outstring; EXPECT_TRUE(iter.ReadString(&outstring)); EXPECT_EQ(teststring, outstring); std::wstring outwstring; EXPECT_TRUE(iter.ReadWString(&outwstring)); EXPECT_EQ(testwstring, outwstring); base::string16 outstring16; EXPECT_TRUE(iter.ReadString16(&outstring16)); EXPECT_EQ(teststring16, outstring16); const char* outdata; int outdatalen; EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen)); EXPECT_EQ(testdatalen, outdatalen); EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); // reads past the end should fail EXPECT_FALSE(iter.ReadInt(&outint)); } } // namespace TEST(PickleTest, EncodeDecode) { Pickle pickle; EXPECT_TRUE(pickle.WriteBool(testbool1)); EXPECT_TRUE(pickle.WriteBool(testbool2)); EXPECT_TRUE(pickle.WriteInt(testint)); EXPECT_TRUE( pickle.WriteLongUsingDangerousNonPortableLessPersistableForm(testlong)); EXPECT_TRUE(pickle.WriteUInt16(testuint16)); EXPECT_TRUE(pickle.WriteUInt32(testuint32)); EXPECT_TRUE(pickle.WriteInt64(testint64)); EXPECT_TRUE(pickle.WriteUInt64(testuint64)); EXPECT_TRUE(pickle.WriteSizeT(testsizet)); EXPECT_TRUE(pickle.WriteFloat(testfloat)); EXPECT_TRUE(pickle.WriteDouble(testdouble)); EXPECT_TRUE(pickle.WriteString(teststring)); EXPECT_TRUE(pickle.WriteWString(testwstring)); EXPECT_TRUE(pickle.WriteString16(teststring16)); EXPECT_TRUE(pickle.WriteData(testdata, testdatalen)); VerifyResult(pickle); // test copy constructor Pickle pickle2(pickle); VerifyResult(pickle2); // test operator= Pickle pickle3; pickle3 = pickle; VerifyResult(pickle3); } // Tests that reading/writing a size_t works correctly when the source process // is 64-bit. We rely on having both 32- and 64-bit trybots to validate both // arms of the conditional in this test. TEST(PickleTest, SizeTFrom64Bit) { Pickle pickle; // Under the hood size_t is always written as a 64-bit value, so simulate a // 64-bit size_t even on 32-bit architectures by explicitly writing a uint64. EXPECT_TRUE(pickle.WriteUInt64(testuint64)); PickleIterator iter(pickle); size_t outsizet; if (sizeof(size_t) < sizeof(uint64)) { // ReadSizeT() should return false when the original written value can't be // represented as a size_t. EXPECT_FALSE(iter.ReadSizeT(&outsizet)); } else { EXPECT_TRUE(iter.ReadSizeT(&outsizet)); EXPECT_EQ(testuint64, outsizet); } } // Tests that we can handle really small buffers. TEST(PickleTest, SmallBuffer) { scoped_ptr buffer(new char[1]); // We should not touch the buffer. Pickle pickle(buffer.get(), 1); PickleIterator iter(pickle); int data; EXPECT_FALSE(iter.ReadInt(&data)); } // Tests that we can handle improper headers. TEST(PickleTest, BigSize) { int buffer[] = { 0x56035200, 25, 40, 50 }; Pickle pickle(reinterpret_cast(buffer), sizeof(buffer)); PickleIterator iter(pickle); int data; EXPECT_FALSE(iter.ReadInt(&data)); } TEST(PickleTest, UnalignedSize) { int buffer[] = { 10, 25, 40, 50 }; Pickle pickle(reinterpret_cast(buffer), sizeof(buffer)); PickleIterator iter(pickle); int data; EXPECT_FALSE(iter.ReadInt(&data)); } TEST(PickleTest, ZeroLenStr) { Pickle pickle; EXPECT_TRUE(pickle.WriteString(std::string())); PickleIterator iter(pickle); std::string outstr; EXPECT_TRUE(iter.ReadString(&outstr)); EXPECT_EQ("", outstr); } TEST(PickleTest, ZeroLenWStr) { Pickle pickle; EXPECT_TRUE(pickle.WriteWString(std::wstring())); PickleIterator iter(pickle); std::string outstr; EXPECT_TRUE(iter.ReadString(&outstr)); EXPECT_EQ("", outstr); } TEST(PickleTest, BadLenStr) { Pickle pickle; EXPECT_TRUE(pickle.WriteInt(-2)); PickleIterator iter(pickle); std::string outstr; EXPECT_FALSE(iter.ReadString(&outstr)); } TEST(PickleTest, BadLenWStr) { Pickle pickle; EXPECT_TRUE(pickle.WriteInt(-1)); PickleIterator iter(pickle); std::wstring woutstr; EXPECT_FALSE(iter.ReadWString(&woutstr)); } TEST(PickleTest, FindNext) { Pickle pickle; EXPECT_TRUE(pickle.WriteInt(1)); EXPECT_TRUE(pickle.WriteString("Domo")); const char* start = reinterpret_cast(pickle.data()); const char* end = start + pickle.size(); EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end)); EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1)); EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1)); } TEST(PickleTest, FindNextWithIncompleteHeader) { size_t header_size = sizeof(Pickle::Header); scoped_ptr buffer(new char[header_size - 1]); memset(buffer.get(), 0x1, header_size - 1); const char* start = buffer.get(); const char* end = start + header_size - 1; EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end)); } #if defined(COMPILER_MSVC) #pragma warning(push) #pragma warning(disable: 4146) #endif TEST(PickleTest, FindNextOverflow) { size_t header_size = sizeof(Pickle::Header); size_t header_size2 = 2 * header_size; size_t payload_received = 100; scoped_ptr buffer(new char[header_size2 + payload_received]); const char* start = buffer.get(); Pickle::Header* header = reinterpret_cast(buffer.get()); const char* end = start + header_size2 + payload_received; // It is impossible to construct an overflow test otherwise. if (sizeof(size_t) > sizeof(header->payload_size) || sizeof(uintptr_t) > sizeof(header->payload_size)) return; header->payload_size = -(reinterpret_cast(start) + header_size2); EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end)); header->payload_size = -header_size2; EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end)); header->payload_size = 0; end = start + header_size; EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end)); } #if defined(COMPILER_MSVC) #pragma warning(pop) #endif TEST(PickleTest, GetReadPointerAndAdvance) { Pickle pickle; PickleIterator iter(pickle); EXPECT_FALSE(iter.GetReadPointerAndAdvance(1)); EXPECT_TRUE(pickle.WriteInt(1)); EXPECT_TRUE(pickle.WriteInt(2)); int bytes = sizeof(int) * 2; EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0)); EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1)); EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1)); EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes)); EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1)); EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX)); EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN)); } TEST(PickleTest, Resize) { size_t unit = Pickle::kPayloadUnit; scoped_ptr data(new char[unit]); char* data_ptr = data.get(); for (size_t i = 0; i < unit; i++) data_ptr[i] = 'G'; // construct a message that will be exactly the size of one payload unit, // note that any data will have a 4-byte header indicating the size const size_t payload_size_after_header = unit - sizeof(uint32); Pickle pickle; pickle.WriteData(data_ptr, static_cast(payload_size_after_header - sizeof(uint32))); size_t cur_payload = payload_size_after_header; // note: we assume 'unit' is a power of 2 EXPECT_EQ(unit, pickle.capacity_after_header()); EXPECT_EQ(pickle.payload_size(), payload_size_after_header); // fill out a full page (noting data header) pickle.WriteData(data_ptr, static_cast(unit - sizeof(uint32))); cur_payload += unit; EXPECT_EQ(unit * 2, pickle.capacity_after_header()); EXPECT_EQ(cur_payload, pickle.payload_size()); // one more byte should double the capacity pickle.WriteData(data_ptr, 1); cur_payload += 8; EXPECT_EQ(unit * 4, pickle.capacity_after_header()); EXPECT_EQ(cur_payload, pickle.payload_size()); } namespace { struct CustomHeader : Pickle::Header { int blah; }; } // namespace TEST(PickleTest, HeaderPadding) { const uint32 kMagic = 0x12345678; Pickle pickle(sizeof(CustomHeader)); pickle.WriteInt(kMagic); // this should not overwrite the 'int' payload pickle.headerT()->blah = 10; PickleIterator iter(pickle); int result; ASSERT_TRUE(iter.ReadInt(&result)); EXPECT_EQ(static_cast(result), kMagic); } TEST(PickleTest, EqualsOperator) { Pickle source; source.WriteInt(1); Pickle copy_refs_source_buffer(static_cast(source.data()), source.size()); Pickle copy; copy = copy_refs_source_buffer; ASSERT_EQ(source.size(), copy.size()); } TEST(PickleTest, EvilLengths) { Pickle source; std::string str(100000, 'A'); EXPECT_TRUE(source.WriteData(str.c_str(), 100000)); // ReadString16 used to have its read buffer length calculation wrong leading // to out-of-bounds reading. PickleIterator iter(source); string16 str16; EXPECT_FALSE(iter.ReadString16(&str16)); // And check we didn't break ReadString16. str16 = (wchar_t) 'A'; Pickle str16_pickle; EXPECT_TRUE(str16_pickle.WriteString16(str16)); iter = PickleIterator(str16_pickle); EXPECT_TRUE(iter.ReadString16(&str16)); EXPECT_EQ(1U, str16.length()); // Check we don't fail in a length check with invalid String16 size. // (1<<31) * sizeof(char16) == 0, so this is particularly evil. Pickle bad_len; EXPECT_TRUE(bad_len.WriteInt(1 << 31)); iter = PickleIterator(bad_len); EXPECT_FALSE(iter.ReadString16(&str16)); // Check we don't fail in a length check with large WStrings. Pickle big_len; EXPECT_TRUE(big_len.WriteInt(1 << 30)); iter = PickleIterator(big_len); std::wstring wstr; EXPECT_FALSE(iter.ReadWString(&wstr)); } // Check we can write zero bytes of data and 'data' can be NULL. TEST(PickleTest, ZeroLength) { Pickle pickle; EXPECT_TRUE(pickle.WriteData(NULL, 0)); PickleIterator iter(pickle); const char* outdata; int outdatalen; EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen)); EXPECT_EQ(0, outdatalen); // We can't assert that outdata is NULL. } // Check that ReadBytes works properly with an iterator initialized to NULL. TEST(PickleTest, ReadBytes) { Pickle pickle; int data = 0x7abcd; EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data))); PickleIterator iter(pickle); const char* outdata_char = NULL; EXPECT_TRUE(iter.ReadBytes(&outdata_char, sizeof(data))); int outdata; memcpy(&outdata, outdata_char, sizeof(outdata)); EXPECT_EQ(data, outdata); }