• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/341324165): Fix and remove.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/containers/buffer_iterator.h"
11 
12 #include <string.h>
13 
14 #include <limits>
15 #include <optional>
16 #include <vector>
17 
18 #include "base/containers/span.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace base {
22 namespace {
23 
24 struct TestStruct {
25   uint32_t one;
26   uint8_t two, three, four, five;
27 };
28 
operator ==(const TestStruct & lhs,const TestStruct & rhs)29 bool operator==(const TestStruct& lhs, const TestStruct& rhs) {
30   return lhs.one == rhs.one && lhs.two == rhs.two;
31 }
32 
CreateTestStruct()33 TestStruct CreateTestStruct() {
34   return {0xabcdef12, 0x34, 0x56, 0x78, 0x90};
35 }
36 
TEST(BufferIteratorTest,Object)37 TEST(BufferIteratorTest, Object) {
38   TestStruct expected = CreateTestStruct();
39 
40   char buffer[sizeof(TestStruct)];
41   memcpy(buffer, &expected, sizeof(buffer));
42 
43   {
44     // Read the object.
45     BufferIterator<char> iterator(buffer);
46     const TestStruct* actual = iterator.Object<TestStruct>();
47     EXPECT_EQ(expected, *actual);
48   }
49   {
50     // Iterator's view of the data is not large enough to read the object.
51     BufferIterator<char> iterator(
52         span<char>(buffer).first<sizeof(buffer) - 1u>());
53     const TestStruct* actual = iterator.Object<TestStruct>();
54     EXPECT_FALSE(actual);
55   }
56 }
57 
TEST(BufferIteratorTest,MutableObject)58 TEST(BufferIteratorTest, MutableObject) {
59   TestStruct expected = CreateTestStruct();
60 
61   char buffer[sizeof(TestStruct)];
62 
63   BufferIterator<char> iterator(buffer);
64 
65   {
66     // Write the object.
67     *iterator.MutableObject<TestStruct>() = expected;
68   }
69 
70   // Rewind the iterator.
71   iterator.Seek(0);
72 
73   {
74     // Read the object back.
75     const TestStruct* actual = iterator.Object<TestStruct>();
76     EXPECT_EQ(expected, *actual);
77   }
78 }
79 
TEST(BufferIteratorTest,ObjectSizeOverflow)80 TEST(BufferIteratorTest, ObjectSizeOverflow) {
81   char buffer[64];
82   BufferIterator<char> iterator(buffer, std::numeric_limits<size_t>::max());
83 
84   auto* pointer = iterator.Object<uint64_t>();
85   EXPECT_TRUE(pointer);
86 
87   iterator.Seek(iterator.total_size() - 1);
88 
89   auto* invalid_pointer = iterator.Object<uint64_t>();
90   EXPECT_FALSE(invalid_pointer);
91 }
92 
TEST(BufferIteratorTest,Span)93 TEST(BufferIteratorTest, Span) {
94   TestStruct expected = CreateTestStruct();
95 
96   std::vector<char> buffer(sizeof(TestStruct) * 3);
97 
98   {
99     // Load the span with data.
100     BufferIterator<char> iterator(buffer);
101     span<TestStruct> span = iterator.MutableSpan<TestStruct>(3);
102     for (auto& ts : span) {
103       memcpy(&ts, &expected, sizeof(expected));
104     }
105   }
106   {
107     // Read the data back out.
108     BufferIterator<char> iterator(buffer);
109 
110     const TestStruct* actual = iterator.Object<TestStruct>();
111     EXPECT_EQ(expected, *actual);
112 
113     actual = iterator.Object<TestStruct>();
114     EXPECT_EQ(expected, *actual);
115 
116     actual = iterator.Object<TestStruct>();
117     EXPECT_EQ(expected, *actual);
118 
119     EXPECT_EQ(iterator.total_size(), iterator.position());
120   }
121   {
122     // Cannot create spans larger than there are data for.
123     BufferIterator<char> iterator(buffer);
124     span<const TestStruct> span = iterator.Span<TestStruct>(4);
125     EXPECT_TRUE(span.empty());
126   }
127 }
128 
TEST(BufferIteratorTest,FixedSpan)129 TEST(BufferIteratorTest, FixedSpan) {
130   TestStruct expected = CreateTestStruct();
131 
132   std::vector<char> buffer(sizeof(TestStruct) * 3);
133 
134   {
135     // Load the span with data.
136     BufferIterator<char> iterator(buffer);
137     auto span = iterator.MutableSpan<TestStruct, 3u>();
138     static_assert(std::same_as<std::optional<base::span<TestStruct, 3u>>,
139                                decltype(span)>);
140     for (auto& ts : *span) {
141       memcpy(&ts, &expected, sizeof(expected));
142     }
143   }
144   {
145     // Read the data back out.
146     BufferIterator<char> iterator(buffer);
147 
148     const TestStruct* actual = iterator.Object<TestStruct>();
149     EXPECT_EQ(expected, *actual);
150 
151     actual = iterator.Object<TestStruct>();
152     EXPECT_EQ(expected, *actual);
153 
154     actual = iterator.Object<TestStruct>();
155     EXPECT_EQ(expected, *actual);
156 
157     EXPECT_EQ(iterator.total_size(), iterator.position());
158   }
159   {
160     // Cannot create spans larger than there are data for.
161     BufferIterator<char> iterator(buffer);
162     auto maybe_span = iterator.Span<TestStruct, 4u>();
163     EXPECT_FALSE(maybe_span.has_value());
164   }
165 }
166 
TEST(BufferIteratorTest,SpanOverflow)167 TEST(BufferIteratorTest, SpanOverflow) {
168   char buffer[64];
169 
170   BufferIterator<char> iterator(
171       // SAFETY: This intentionally makes an incorrectly-sized span. The span
172       // pointer, stored in the BufferIterator is never moved past the start in
173       // this test, as that would cause Undefined Behaviour.
174       UNSAFE_BUFFERS(span(buffer, std::numeric_limits<size_t>::max())));
175 
176   constexpr size_t kInvalidU64Size =
177       (std::numeric_limits<size_t>::max() / sizeof(uint64_t)) + 1u;
178   {
179     span<const uint64_t> empty_span = iterator.Span<uint64_t>(kInvalidU64Size);
180     EXPECT_TRUE(empty_span.empty());
181   }
182   {
183     span<const uint64_t> empty_span =
184         iterator.Span<uint64_t>(std::numeric_limits<size_t>::max());
185     EXPECT_TRUE(empty_span.empty());
186   }
187 }
188 
TEST(BufferIteratorTest,Position)189 TEST(BufferIteratorTest, Position) {
190   char buffer[64];
191   BufferIterator<char> iterator(buffer);
192   EXPECT_EQ(sizeof(buffer), iterator.total_size());
193 
194   size_t position = iterator.position();
195   EXPECT_EQ(0u, position);
196 
197   iterator.Object<uint8_t>();
198   EXPECT_EQ(sizeof(uint8_t), iterator.position() - position);
199   position = iterator.position();
200 
201   iterator.Object<uint32_t>();
202   EXPECT_EQ(sizeof(uint32_t), iterator.position() - position);
203   position = iterator.position();
204 
205   iterator.Seek(32);
206   EXPECT_EQ(32u, iterator.position());
207 
208   EXPECT_EQ(sizeof(buffer), iterator.total_size());
209 }
210 
TEST(BufferIteratorTest,CopyObject)211 TEST(BufferIteratorTest, CopyObject) {
212   TestStruct expected = CreateTestStruct();
213 
214   constexpr int kNumCopies = 3;
215   char buffer[sizeof(TestStruct) * kNumCopies];
216   for (int i = 0; i < kNumCopies; i++) {
217     as_writable_bytes(span(buffer))
218         .subspan(i * sizeof(TestStruct))
219         .first<sizeof(TestStruct)>()
220         .copy_from(byte_span_from_ref(expected));
221   }
222 
223   BufferIterator<char> iterator(buffer);
224   std::optional<TestStruct> actual;
225   for (int i = 0; i < kNumCopies; i++) {
226     actual = iterator.CopyObject<TestStruct>();
227     ASSERT_TRUE(actual.has_value());
228     EXPECT_EQ(expected, *actual);
229   }
230   actual = iterator.CopyObject<TestStruct>();
231   EXPECT_FALSE(actual.has_value());
232 }
233 
TEST(BufferIteratorTest,SeekWithSizeConfines)234 TEST(BufferIteratorTest, SeekWithSizeConfines) {
235   const char buffer[] = "vindicate";
236   BufferIterator<const char> iterator(base::span_from_cstring(buffer));
237   iterator.Seek(5);
238   iterator.TruncateTo(3);
239   EXPECT_TRUE(iterator.Span<char>(4).empty());
240 
241   std::string result;
242   while (const char* c = iterator.Object<char>())
243     result += *c;
244   EXPECT_EQ(result, "cat");
245 }
246 
247 }  // namespace
248 }  // namespace base
249