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