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