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