Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /base /pickle_unittest.cc
blob: 6488057b28562383824d05d7ffe9134db680731f [file] [log] [blame] [edit]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include"base/pickle.h"
#include<limits.h>
#include<stddef.h>
#include<stdint.h>
#include<memory>
#include<string>
#include<string_view>
#include<tuple>
#include"base/containers/heap_array.h"
#include"base/containers/span.h"
#include"base/strings/utf_string_conversions.h"
#include"build/build_config.h"
#include"testing/gmock/include/gmock/gmock.h"
#include"testing/gtest/include/gtest/gtest.h"
namespace base{
namespace{
constbool testbool1=false;
constbool testbool2=true;
constint testint=2'093'847'192;
constlong testlong=1'093'847'192;
constuint16_t testuint16=32123;
constuint32_t testuint32=1593847192;
constint64_t testint64=-0x7E8CA925'3104BDFCLL;
constuint64_t testuint64=0xCE8CA925'3104BDF7ULL;
constfloat testfloat=3.1415926935f;
constdouble testdouble=2.71828182845904523;
const std::string teststring("Hello world");// note non-aligned string length
const std::string testemptystring("");
const std::wstring testwstring(L"Hello, world");
const std::u16string teststring16(u"Hello, world");
constchar testrawstring[]="Hello new world";// Test raw string writing
// Test raw char16_t writing, assumes UTF16 encoding is ANSI for alpha chars.
constchar16_t testrawstring16[]={'A','l','o','h','a',0};
constchar testdata[]="AAA\0BBB\0";
constsize_t testdatalen= std::size(testdata)-1;
// checks that the results can be read correctly from the Pickle
voidVerifyResult(constPickle& 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_t outuint16;
EXPECT_TRUE(iter.ReadUInt16(&outuint16));
EXPECT_EQ(testuint16, outuint16);
uint32_t outuint32;
EXPECT_TRUE(iter.ReadUInt32(&outuint32));
EXPECT_EQ(testuint32, outuint32);
int64_t outint64;
EXPECT_TRUE(iter.ReadInt64(&outint64));
EXPECT_EQ(testint64, outint64);
uint64_t outuint64;
EXPECT_TRUE(iter.ReadUInt64(&outuint64));
EXPECT_EQ(testuint64, outuint64);
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::string outstring2;
EXPECT_TRUE(iter.ReadString(&outstring2));
EXPECT_EQ(testemptystring, outstring2);
std::u16string outstring16;
EXPECT_TRUE(iter.ReadString16(&outstring16));
EXPECT_EQ(teststring16, outstring16);
std::string_view outstringpiece;
EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece));
EXPECT_EQ(testrawstring, outstringpiece);
std::u16string_view outstringpiece16;
EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16));
EXPECT_EQ(testrawstring16, outstringpiece16);
constchar* outdata;
size_t 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,UnownedVsOwned){
constuint8_t buffer[1]={0x00};
Pickle unowned_pickle=Pickle::WithUnownedBuffer(buffer);
EXPECT_EQ(unowned_pickle.GetTotalAllocatedSize(),0u);
Pickle owned_pickle=Pickle::WithData(buffer);
EXPECT_GE(unowned_pickle.GetTotalAllocatedSize(),0u);
}
TEST(PickleTest,EncodeDecode){
Pickle pickle;
pickle.WriteBool(testbool1);
pickle.WriteBool(testbool2);
pickle.WriteInt(testint);
pickle.WriteLong(testlong);
pickle.WriteUInt16(testuint16);
pickle.WriteUInt32(testuint32);
pickle.WriteInt64(testint64);
pickle.WriteUInt64(testuint64);
pickle.WriteFloat(testfloat);
pickle.WriteDouble(testdouble);
pickle.WriteString(teststring);
pickle.WriteString(testemptystring);
pickle.WriteString16(teststring16);
pickle.WriteString(testrawstring);
pickle.WriteString16(testrawstring16);
pickle.WriteData(std::string_view(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 long 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,LongFrom64Bit){
Pickle pickle;
// Under the hood long is always written as a 64-bit value, so simulate a
// 64-bit long even on 32-bit architectures by explicitly writing an int64_t.
pickle.WriteInt64(testint64);
PickleIterator iter(pickle);
long outlong;
if(sizeof(long)<sizeof(int64_t)){
// ReadLong() should return false when the original written value can't be
// represented as a long.
EXPECT_FALSE(iter.ReadLong(&outlong));
}else{
EXPECT_TRUE(iter.ReadLong(&outlong));
EXPECT_EQ(testint64, outlong);
}
}
// Tests that we can handle really small buffers.
TEST(PickleTest,SmallBuffer){
constuint8_t buffer[]={0x00};
// We should not touch the buffer.
Pickle pickle=Pickle::WithUnownedBuffer(buffer);
PickleIterator iter(pickle);
int data;
EXPECT_FALSE(iter.ReadInt(&data));
}
// Tests that we can handle improper headers.
TEST(PickleTest,BigSize){
constint buffer[4]={0x56035200,25,40,50};
Pickle pickle=Pickle::WithUnownedBuffer(as_byte_span(buffer));
EXPECT_EQ(0U, pickle.size());
PickleIterator iter(pickle);
int data;
EXPECT_FALSE(iter.ReadInt(&data));
}
// Tests that instances constructed with invalid parameter combinations can be
// properly copied. Regression test for https://crbug.com/1271311.
TEST(PickleTest,CopyWithInvalidHeader){
// 1. Actual header size (calculated based on the input buffer) > passed in
// buffer size. Which results in Pickle's internal |header_| = null.
{
Pickle::Header header={.payload_size=100};
constPickle pickle=Pickle::WithUnownedBuffer(byte_span_from_ref(header));
EXPECT_EQ(0U, pickle.size());
EXPECT_FALSE(pickle.data());
Pickle copy_built_with_op= pickle;
EXPECT_EQ(0U, copy_built_with_op.size());
EXPECT_FALSE(copy_built_with_op.data());
Pickle copy_built_with_ctor(pickle);
EXPECT_EQ(0U, copy_built_with_ctor.size());
EXPECT_FALSE(copy_built_with_ctor.data());
}
// 2. Input buffer's size < sizeof(Pickle::Header). Which must also result in
// Pickle's internal |header_| = null.
{
constuint8_t data[]={0x00,0x00};
constPickle pickle=Pickle::WithUnownedBuffer(data);
static_assert(sizeof(Pickle::Header)>sizeof(data));
EXPECT_EQ(0U, pickle.size());
EXPECT_FALSE(pickle.data());
Pickle copy_built_with_op= pickle;
EXPECT_EQ(0U, copy_built_with_op.size());
EXPECT_FALSE(copy_built_with_op.data());
Pickle copy_built_with_ctor(pickle);
EXPECT_EQ(0U, copy_built_with_ctor.size());
EXPECT_FALSE(copy_built_with_ctor.data());
}
}
TEST(PickleTest,UnalignedSize){
int buffer[]={10,25,40,50};
Pickle pickle=Pickle::WithUnownedBuffer(as_byte_span(buffer));
PickleIterator iter(pickle);
int data;
EXPECT_FALSE(iter.ReadInt(&data));
}
TEST(PickleTest,ZeroLenStr){
Pickle pickle;
pickle.WriteString(std::string());
PickleIterator iter(pickle);
std::string outstr;
EXPECT_TRUE(iter.ReadString(&outstr));
EXPECT_EQ("", outstr);
}
TEST(PickleTest,ZeroLenStr16){
Pickle pickle;
pickle.WriteString16(std::u16string());
PickleIterator iter(pickle);
std::string outstr;
EXPECT_TRUE(iter.ReadString(&outstr));
EXPECT_EQ("", outstr);
}
TEST(PickleTest,BadLenStr){
Pickle pickle;
pickle.WriteInt(-2);
PickleIterator iter(pickle);
std::string outstr;
EXPECT_FALSE(iter.ReadString(&outstr));
}
TEST(PickleTest,BadLenStr16){
Pickle pickle;
pickle.WriteInt(-1);
PickleIterator iter(pickle);
std::u16string outstr;
EXPECT_FALSE(iter.ReadString16(&outstr));
}
TEST(PickleTest,PeekNext){
structCustomHeader: base::Pickle::Header{
int cookies[10];
};
Pickle pickle(sizeof(CustomHeader));
pickle.WriteString("Goooooooooooogle");
constchar* pickle_data= pickle.data_as_char();
size_t pickle_size;
// Data range doesn't contain header
EXPECT_FALSE(Pickle::PeekNext(sizeof(CustomHeader), pickle_data,
pickle_data+sizeof(CustomHeader)-1,
&pickle_size));
// Data range contains header
EXPECT_TRUE(Pickle::PeekNext(sizeof(CustomHeader), pickle_data,
pickle_data+sizeof(CustomHeader),
&pickle_size));
EXPECT_EQ(pickle_size, pickle.size());
// Data range contains header and some other data
EXPECT_TRUE(Pickle::PeekNext(sizeof(CustomHeader), pickle_data,
pickle_data+sizeof(CustomHeader)+1,
&pickle_size));
EXPECT_EQ(pickle_size, pickle.size());
// Data range contains full pickle
EXPECT_TRUE(Pickle::PeekNext(sizeof(CustomHeader), pickle_data,
pickle_data+ pickle.size(),&pickle_size));
EXPECT_EQ(pickle_size, pickle.size());
}
TEST(PickleTest,PeekNextOverflow){
structCustomHeader: base::Pickle::Header{
int cookies[10];
};
CustomHeader header;
// Check if we can wrap around at all
if(sizeof(size_t)>sizeof(header.payload_size)){
return;
}
constchar* pickle_data=reinterpret_cast<constchar*>(&header);
size_t pickle_size;
// Wrapping around is detected and reported as maximum size_t value
header.payload_size=
static_cast<uint32_t>(1-static_cast<int32_t>(sizeof(CustomHeader)));
EXPECT_TRUE(Pickle::PeekNext(sizeof(CustomHeader), pickle_data,
pickle_data+sizeof(CustomHeader),
&pickle_size));
EXPECT_EQ(pickle_size, std::numeric_limits<size_t>::max());
// Ridiculous pickle sizes are fine (callers are supposed to
// verify them)
header.payload_size=
std::numeric_limits<uint32_t>::max()/2-sizeof(CustomHeader);
EXPECT_TRUE(Pickle::PeekNext(sizeof(CustomHeader), pickle_data,
pickle_data+sizeof(CustomHeader),
&pickle_size));
EXPECT_EQ(pickle_size, std::numeric_limits<uint32_t>::max()/2);
}
TEST(PickleTest,FindNext){
Pickle pickle;
pickle.WriteInt(1);
pickle.WriteString("Domo");
constchar* start=reinterpret_cast<constchar*>(pickle.data());
constchar* end= start+ pickle.size();
EXPECT_EQ(end,Pickle::FindNext(pickle.header_size_, start, end));
EXPECT_EQ(nullptr,Pickle::FindNext(pickle.header_size_, start, end-1));
EXPECT_EQ(end,Pickle::FindNext(pickle.header_size_, start, end+1));
}
TEST(PickleTest,FindNextWithIncompleteHeader){
size_t header_size=sizeof(Pickle::Header);
auto buffer= base::HeapArray<char>::Uninit(header_size-1);
memset(buffer.data(),0x1, header_size-1);
constchar* start= buffer.data();
constchar* end= start+ header_size-1;
EXPECT_EQ(nullptr,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;
auto buffer= base::HeapArray<char>::Uninit(header_size2+ payload_received);
constchar* start= buffer.data();
Pickle::Header* header=reinterpret_cast<Pickle::Header*>(buffer.data());
constchar* 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<uintptr_t>(start)+ header_size2);
EXPECT_EQ(nullptr,Pickle::FindNext(header_size2, start, end));
header->payload_size=-header_size2;
EXPECT_EQ(nullptr,Pickle::FindNext(header_size2, start, end));
header->payload_size=0;
end= start+ header_size;
EXPECT_EQ(nullptr,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));
pickle.WriteInt(1);
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;
auto data= base::HeapArray<char>::Uninit(unit);
char* data_ptr= data.data();
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
constsize_t payload_size_after_header= unit-sizeof(uint32_t);
Pickle pickle;
pickle.WriteData(
std::string_view(data_ptr, payload_size_after_header-sizeof(uint32_t)));
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(std::string_view(data_ptr, unit-sizeof(uint32_t)));
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(std::string_view(data_ptr,1u));
cur_payload+=8;
EXPECT_EQ(unit*4, pickle.capacity_after_header());
EXPECT_EQ(cur_payload, pickle.payload_size());
}
namespace{
structCustomHeader:Pickle::Header{
int blah;
};
}// namespace
TEST(PickleTest,HeaderPadding){
constuint32_t kMagic=0x12345678;
Pickle pickle(sizeof(CustomHeader));
pickle.WriteInt(kMagic);
// this should not overwrite the 'int' payload
pickle.headerT<CustomHeader>()->blah=10;
PickleIterator iter(pickle);
int result;
ASSERT_TRUE(iter.ReadInt(&result));
EXPECT_EQ(static_cast<uint32_t>(result), kMagic);
}
TEST(PickleTest,EqualsOperator){
Pickle source;
source.WriteInt(1);
Pickle copy_refs_source_buffer=Pickle::WithUnownedBuffer(source);
Pickle copy;
copy= copy_refs_source_buffer;
ASSERT_EQ(source.size(), copy.size());
}
TEST(PickleTest,EvilLengths){
Pickle source;
std::string str(100000,'A');
source.WriteData(std::string_view(str.c_str(),100000u));
// ReadString16 used to have its read buffer length calculation wrong leading
// to out-of-bounds reading.
PickleIterator iter(source);
std::u16string str16;
EXPECT_FALSE(iter.ReadString16(&str16));
// And check we didn't break ReadString16.
str16= u"A";
Pickle str16_pickle;
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_t) == 0, so this is particularly evil.
Pickle bad_len;
bad_len.WriteInt(1<<31);
iter=PickleIterator(bad_len);
EXPECT_FALSE(iter.ReadString16(&str16));
}
// Check we can write zero bytes of data and 'data' can be NULL.
TEST(PickleTest,ZeroLength){
Pickle pickle;
pickle.WriteData(std::string_view());
PickleIterator iter(pickle);
constchar* outdata;
size_t outdatalen;
EXPECT_TRUE(iter.ReadData(&outdata,&outdatalen));
EXPECT_EQ(0u, 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;
pickle.WriteBytes(&data,sizeof(data));
PickleIterator iter(pickle);
constchar* outdata_char=nullptr;
EXPECT_TRUE(iter.ReadBytes(&outdata_char,sizeof(data)));
int outdata;
memcpy(&outdata, outdata_char,sizeof(outdata));
EXPECT_EQ(data, outdata);
}
// Checks that when a pickle is deep-copied, the result is not larger than
// needed.
TEST(PickleTest,DeepCopyResize){
Pickle pickle;
while(pickle.capacity_after_header()!= pickle.payload_size()){
pickle.WriteBool(true);
}
// Make a deep copy.
Pickle pickle2(pickle);
// Check that there isn't any extraneous capacity.
EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header());
}
namespace{
// Publicly exposes the ClaimBytes interface for testing.
classTestingPickle:publicPickle{
public:
TestingPickle()=default;
void*ClaimBytes(size_t num_bytes){returnPickle::ClaimBytes(num_bytes);}
};
}// namespace
// Checks that claimed bytes are zero-initialized.
TEST(PickleTest,ClaimBytesInitialization){
staticconstint kChunkSize=64;
TestingPickle pickle;
constchar* bytes=static_cast<constchar*>(pickle.ClaimBytes(kChunkSize));
for(size_t i=0; i< kChunkSize;++i){
EXPECT_EQ(0, bytes[i]);
}
}
// Checks that ClaimBytes properly advances the write offset.
TEST(PickleTest,ClaimBytes){
std::string data("Hello, world!");
TestingPickle pickle;
pickle.WriteUInt32(data.size());
void* bytes= pickle.ClaimBytes(data.size());
pickle.WriteInt(42);
memcpy(bytes, data.data(), data.size());
PickleIterator iter(pickle);
uint32_t out_data_length;
EXPECT_TRUE(iter.ReadUInt32(&out_data_length));
EXPECT_EQ(data.size(), out_data_length);
constchar* out_data=nullptr;
EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length));
EXPECT_EQ(data, std::string(out_data, out_data_length));
int out_value;
EXPECT_TRUE(iter.ReadInt(&out_value));
EXPECT_EQ(42, out_value);
}
TEST(PickleTest,ReachedEnd){
Pickle pickle;
pickle.WriteInt(1);
pickle.WriteInt(2);
pickle.WriteInt(3);
PickleIterator iter(pickle);
int out;
EXPECT_FALSE(iter.ReachedEnd());
EXPECT_TRUE(iter.ReadInt(&out));
EXPECT_EQ(1, out);
EXPECT_FALSE(iter.ReachedEnd());
EXPECT_TRUE(iter.ReadInt(&out));
EXPECT_EQ(2, out);
EXPECT_FALSE(iter.ReachedEnd());
EXPECT_TRUE(iter.ReadInt(&out));
EXPECT_EQ(3, out);
EXPECT_TRUE(iter.ReachedEnd());
EXPECT_FALSE(iter.ReadInt(&out));
EXPECT_TRUE(iter.ReachedEnd());
}
// Test that reading a value other than 0 or 1 as a bool does not trigger
// UBSan.
TEST(PickleTest,NonCanonicalBool){
Pickle pickle;
pickle.WriteInt(0xff);
PickleIterator iter(pickle);
bool b;
ASSERT_TRUE(iter.ReadBool(&b));
EXPECT_TRUE(b);
}
// Tests the ReadData() overload that returns a span.
TEST(PickleTest,ReadDataAsSpan){
constexprauto kWriteData=
std::to_array<uint8_t>({0x01,0x02,0x03,0x61,0x62,0x63});
Pickle pickle;
pickle.WriteData(kWriteData);
pickle.WriteData(base::span<constuint8_t>());
PickleIterator iter(pickle);
EXPECT_THAT(iter.ReadData(), testing::Optional(kWriteData));
EXPECT_THAT(iter.ReadData(), testing::Optional(base::span<constuint8_t>()));
EXPECT_FALSE(iter.ReadData());
}
// Tests the ReadBytes() overload that returns a span.
TEST(PickleTest,ReadBytesAsSpan){
constexprauto kWriteData=
std::to_array<uint8_t>({0x01,0x02,0x03,0x61,0x62,0x63});
Pickle pickle;
pickle.WriteBytes(kWriteData);
PickleIterator iter(pickle);
EXPECT_THAT(iter.ReadBytes(kWriteData.size()), testing::Optional(kWriteData));
EXPECT_FALSE(iter.ReadBytes(kWriteData.size()));
}
}// namespace base

[8]ページ先頭

©2009-2025 Movatter.jp