• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "offset64_test.h"
2 
3 #include <stdint.h>
4 
5 #include <cstdint>
6 #include <fstream>
7 #include <limits>
8 #include <ostream>
9 
10 #include "flatbuffers/base.h"
11 #include "flatbuffers/buffer.h"
12 #include "flatbuffers/flatbuffer_builder.h"
13 #include "flatbuffers/flatbuffers.h"
14 #include "tests/64bit/evolution/v1_generated.h"
15 #include "tests/64bit/evolution/v2_generated.h"
16 #include "tests/64bit/test_64bit_generated.h"
17 #include "tests/test_assert.h"
18 
19 namespace flatbuffers {
20 namespace tests {
21 
Offset64Test()22 void Offset64Test() {
23   FlatBufferBuilder64 builder;
24 
25   const size_t far_vector_size = 1LL << 2;
26   // Make a large number if wanting to test a real large buffer.
27   const size_t big_vector_size = 1LL << 2;
28 
29   {
30     // First create the vectors that will be copied to the buffer.
31     std::vector<uint8_t> far_data;
32     far_data.resize(far_vector_size);
33     far_data[0] = 4;
34     far_data[far_vector_size - 1] = 2;
35 
36     std::vector<uint8_t> big_data;
37     big_data.resize(big_vector_size);
38     big_data[0] = 8;
39     big_data[big_vector_size - 1] = 3;
40 
41     // Then serialize all the fields that have 64-bit offsets, as these must be
42     // serialized before any 32-bit fields are added to the buffer.
43     const Offset64<Vector<uint8_t>> far_vector_offset =
44         builder.CreateVector64<Vector>(far_data);
45 
46     const Offset64<String> far_string_offset =
47         builder.CreateString<Offset64>("some far string");
48 
49     const Offset64<Vector64<uint8_t>> big_vector_offset =
50         builder.CreateVector64(big_data);
51 
52     // Now that we are done with the 64-bit fields, we can create and add the
53     // normal fields.
54     const Offset<String> near_string_offset =
55         builder.CreateString("some near string");
56 
57     // Finish by building the root table by passing in all the offsets.
58     const Offset<RootTable> root_table_offset =
59         CreateRootTable(builder, far_vector_offset, 0, far_string_offset,
60                         big_vector_offset, near_string_offset);
61 
62     // Finish the buffer.
63     builder.Finish(root_table_offset);
64 
65     Verifier::Options options;
66     // Allow the verifier to verify 64-bit buffers.
67     options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
68     options.assert = true;
69 
70     Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
71 
72     TEST_EQ(VerifyRootTableBuffer(verifier), true);
73   }
74 
75   {
76     const RootTable *root_table = GetRootTable(builder.GetBufferPointer());
77 
78     // Expect the far vector to be properly sized.
79     TEST_EQ(root_table->far_vector()->size(), far_vector_size);
80     TEST_EQ(root_table->far_vector()->Get(0), 4);
81     TEST_EQ(root_table->far_vector()->Get(far_vector_size - 1), 2);
82 
83     TEST_EQ_STR(root_table->far_string()->c_str(), "some far string");
84 
85     // Expect the big vector to be properly sized.
86     TEST_EQ(root_table->big_vector()->size(), big_vector_size);
87     TEST_EQ(root_table->big_vector()->Get(0), 8);
88     TEST_EQ(root_table->big_vector()->Get(big_vector_size - 1), 3);
89 
90     TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
91   }
92 }
93 
Offset64SerializedFirst()94 void Offset64SerializedFirst() {
95   FlatBufferBuilder64 fbb;
96 
97   // First create the vectors that will be copied to the buffer.
98   std::vector<uint8_t> data;
99   data.resize(64);
100 
101   // Then serialize all the fields that have 64-bit offsets, as these must be
102   // serialized before any 32-bit fields are added to the buffer.
103   fbb.CreateVector64(data);
104 
105   // TODO(derekbailey): figure out how to test assertions.
106   // Uncommenting this line should fail the test with an assertion.
107   // fbb.CreateString("some near string");
108 
109   fbb.CreateVector64(data);
110 }
111 
Offset64NestedFlatBuffer()112 void Offset64NestedFlatBuffer() {
113   FlatBufferBuilder64 fbb;
114 
115   // First serialize a nested buffer.
116   const Offset<String> near_string_offset =
117       fbb.CreateString("nested: some near string");
118 
119   // Finish by building the root table by passing in all the offsets.
120   const Offset<RootTable> root_table_offset =
121       CreateRootTable(fbb, 0, 0, 0, 0, near_string_offset, 0);
122 
123   // Finish the buffer.
124   fbb.Finish(root_table_offset);
125 
126   // Ensure the buffer is valid.
127   const RootTable *root_table = GetRootTable(fbb.GetBufferPointer());
128   TEST_EQ_STR(root_table->near_string()->c_str(), "nested: some near string");
129 
130   // Copy the data out of the builder.
131   std::vector<uint8_t> nested_data{ fbb.GetBufferPointer(),
132                                     fbb.GetBufferPointer() + fbb.GetSize() };
133 
134   {
135     // Clear so we can reuse the builder.
136     fbb.Clear();
137 
138     const Offset64<Vector64<uint8_t>> nested_flatbuffer_offset =
139         fbb.CreateVector64<Vector64>(nested_data);
140 
141     // Now that we are done with the 64-bit fields, we can create and add the
142     // normal fields.
143     const Offset<String> near_string_offset =
144         fbb.CreateString("some near string");
145 
146     // Finish by building the root table by passing in all the offsets.
147     const Offset<RootTable> root_table_offset = CreateRootTable(
148         fbb, 0, 0, 0, 0, near_string_offset, nested_flatbuffer_offset);
149 
150     // Finish the buffer.
151     fbb.Finish(root_table_offset);
152 
153     Verifier::Options options;
154     // Allow the verifier to verify 64-bit buffers.
155     options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
156     options.assert = true;
157 
158     Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize(), options);
159 
160     TEST_EQ(VerifyRootTableBuffer(verifier), true);
161   }
162 
163   {
164     const RootTable *root_table = GetRootTable(fbb.GetBufferPointer());
165 
166     // Test that the parent buffer field is ok.
167     TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
168 
169     // Expect nested buffer to be properly sized.
170     TEST_EQ(root_table->nested_root()->size(), nested_data.size());
171 
172     // Expect the direct accessors to the nested buffer work.
173     TEST_EQ_STR(root_table->nested_root_nested_root()->near_string()->c_str(),
174                 "nested: some near string");
175   }
176 }
177 
Offset64CreateDirect()178 void Offset64CreateDirect() {
179   FlatBufferBuilder64 fbb;
180 
181   // Create a vector of some data
182   std::vector<uint8_t> data{ 0, 1, 2 };
183 
184   // Call the "Direct" creation method to ensure that things are added to the
185   // buffer in the correct order, Offset64 first followed by any Offsets.
186   const Offset<RootTable> root_table_offset = CreateRootTableDirect(
187       fbb, &data, 0, "some far string", &data, "some near string");
188 
189   // Finish the buffer.
190   fbb.Finish(root_table_offset);
191 
192   Verifier::Options options;
193   // Allow the verifier to verify 64-bit buffers.
194   options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
195   options.assert = true;
196 
197   Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize(), options);
198 
199   TEST_EQ(VerifyRootTableBuffer(verifier), true);
200 
201   // Verify the data.
202   const RootTable *root_table = GetRootTable(fbb.GetBufferPointer());
203   TEST_EQ(root_table->far_vector()->size(), data.size());
204   TEST_EQ(root_table->big_vector()->size(), data.size());
205   TEST_EQ_STR(root_table->far_string()->c_str(), "some far string");
206   TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
207 }
208 
Offset64Evolution()209 void Offset64Evolution() {
210   // Some common data for the tests.
211   const std::vector<uint8_t> data = { 1, 2, 3, 4 };
212   const std::vector<uint8_t> big_data = { 6, 7, 8, 9, 10 };
213 
214   // Built V1 read V2
215   {
216     // Use the 32-bit builder since V1 doesn't have any 64-bit offsets.
217     FlatBufferBuilder builder;
218 
219     builder.Finish(v1::CreateRootTableDirect(builder, 1234, &data));
220 
221     // Use each version to get a view at the root table.
222     auto v1_root = v1::GetRootTable(builder.GetBufferPointer());
223     auto v2_root = v2::GetRootTable(builder.GetBufferPointer());
224 
225     // Test field equivalents for fields common to V1 and V2.
226     TEST_EQ(v1_root->a(), v2_root->a());
227 
228     TEST_EQ(v1_root->b(), v2_root->b());
229     TEST_EQ(v1_root->b()->Get(2), 3);
230     TEST_EQ(v2_root->b()->Get(2), 3);
231 
232     // This field is added in V2, so it should be null since V1 couldn't have
233     // written it.
234     TEST_ASSERT(v2_root->big_vector() == nullptr);
235   }
236 
237   // Built V2 read V1
238   {
239     // Use the 64-bit builder since V2 has 64-bit offsets.
240     FlatBufferBuilder64 builder;
241 
242     builder.Finish(v2::CreateRootTableDirect(builder, 1234, &data, &big_data));
243 
244     // Use each version to get a view at the root table.
245     auto v1_root = v1::GetRootTable(builder.GetBufferPointer());
246     auto v2_root = v2::GetRootTable(builder.GetBufferPointer());
247 
248     // Test field equivalents for fields common to V1 and V2.
249     TEST_EQ(v1_root->a(), v2_root->a());
250 
251     TEST_EQ(v1_root->b(), v2_root->b());
252     TEST_EQ(v1_root->b()->Get(2), 3);
253     TEST_EQ(v2_root->b()->Get(2), 3);
254 
255     // Test that V2 can read the big vector, which V1 doesn't even have
256     // accessors for (i.e. v1_root->big_vector() doesn't exist).
257     TEST_ASSERT(v2_root->big_vector() != nullptr);
258     TEST_EQ(v2_root->big_vector()->size(), big_data.size());
259     TEST_EQ(v2_root->big_vector()->Get(2), 8);
260   }
261 
262   // Built V2 read V1, bigger than max 32-bit buffer sized.
263   // This checks that even a large buffer can still be read by V1.
264   {
265     // Use the 64-bit builder since V2 has 64-bit offsets.
266     FlatBufferBuilder64 builder;
267 
268     std::vector<uint8_t> giant_data;
269     giant_data.resize(1LL << 3);
270     giant_data[2] = 42;
271 
272     builder.Finish(
273         v2::CreateRootTableDirect(builder, 1234, &data, &giant_data));
274 
275     // Use each version to get a view at the root table.
276     auto v1_root = v1::GetRootTable(builder.GetBufferPointer());
277     auto v2_root = v2::GetRootTable(builder.GetBufferPointer());
278 
279     // Test field equivalents for fields common to V1 and V2.
280     TEST_EQ(v1_root->a(), v2_root->a());
281 
282     TEST_EQ(v1_root->b(), v2_root->b());
283     TEST_EQ(v1_root->b()->Get(2), 3);
284     TEST_EQ(v2_root->b()->Get(2), 3);
285 
286     // Test that V2 can read the big vector, which V1 doesn't even have
287     // accessors for (i.e. v1_root->big_vector() doesn't exist).
288     TEST_ASSERT(v2_root->big_vector() != nullptr);
289     TEST_EQ(v2_root->big_vector()->size(), giant_data.size());
290     TEST_EQ(v2_root->big_vector()->Get(2), 42);
291   }
292 }
293 
Offset64VectorOfStructs()294 void Offset64VectorOfStructs() {
295   FlatBufferBuilder64 builder;
296 
297   std::vector<LeafStruct> far_leaves;
298   far_leaves.emplace_back(LeafStruct{ 123, 4.567 });
299   far_leaves.emplace_back(LeafStruct{ 987, 6.543 });
300 
301   std::vector<LeafStruct> big_leaves;
302   big_leaves.emplace_back(LeafStruct{ 72, 72.8 });
303   big_leaves.emplace_back(LeafStruct{ 82, 82.8 });
304   big_leaves.emplace_back(LeafStruct{ 92, 92.8 });
305 
306   // Add the two vectors of leaf structs.
307   const Offset<RootTable> root_table_offset =
308       CreateRootTableDirect(builder, nullptr, 0, nullptr, nullptr, nullptr,
309                             nullptr, &far_leaves, &big_leaves);
310 
311   // Finish the buffer.
312   builder.Finish(root_table_offset);
313 
314   Verifier::Options options;
315   // Allow the verifier to verify 64-bit buffers.
316   options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
317   options.assert = true;
318 
319   Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
320 
321   TEST_EQ(VerifyRootTableBuffer(verifier), true);
322 
323   // Verify the data.
324   const RootTable *root_table = GetRootTable(builder.GetBufferPointer());
325   TEST_EQ(root_table->far_struct_vector()->size(), far_leaves.size());
326   TEST_EQ(root_table->far_struct_vector()->Get(0)->a(), 123);
327   TEST_EQ(root_table->far_struct_vector()->Get(0)->b(), 4.567);
328   TEST_EQ(root_table->far_struct_vector()->Get(1)->a(), 987);
329   TEST_EQ(root_table->far_struct_vector()->Get(1)->b(), 6.543);
330 
331   TEST_EQ(root_table->big_struct_vector()->size(), big_leaves.size());
332   TEST_EQ(root_table->big_struct_vector()->Get(0)->a(), 72);
333   TEST_EQ(root_table->big_struct_vector()->Get(0)->b(), 72.8);
334   TEST_EQ(root_table->big_struct_vector()->Get(1)->a(), 82);
335   TEST_EQ(root_table->big_struct_vector()->Get(1)->b(), 82.8);
336   TEST_EQ(root_table->big_struct_vector()->Get(2)->a(), 92);
337   TEST_EQ(root_table->big_struct_vector()->Get(2)->b(), 92.8);
338 }
339 
Offset64SizePrefix()340 void Offset64SizePrefix() {
341   FlatBufferBuilder64 builder;
342 
343   // First serialize a nested buffer.
344   const Offset<String> near_string_offset =
345       builder.CreateString("some near string");
346 
347   // Finish by building the root table by passing in all the offsets.
348   const Offset<RootTable> root_table_offset =
349       CreateRootTable(builder, 0, 0, 0, 0, near_string_offset, 0);
350 
351   // Finish the buffer.
352   FinishSizePrefixedRootTableBuffer(builder, root_table_offset);
353 
354   TEST_EQ(GetPrefixedSize<uoffset64_t>(builder.GetBufferPointer()),
355           builder.GetSize() - sizeof(uoffset64_t));
356 
357   Verifier::Options options;
358   // Allow the verifier to verify 64-bit buffers.
359   options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
360   options.assert = true;
361 
362   Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
363 
364   TEST_EQ(VerifySizePrefixedRootTableBuffer(verifier), true);
365 
366   const RootTable *root_table =
367       GetSizePrefixedRootTable(builder.GetBufferPointer());
368 
369   // Verify the fields.
370   TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
371 }
372 
Offset64ManyVectors()373 void Offset64ManyVectors() {
374   FlatBufferBuilder64 builder;
375 
376   // Setup some data to serialize.
377   std::vector<int8_t> data;
378   data.resize(20);
379   data.front() = 42;
380   data.back() = 18;
381 
382   const size_t kNumVectors = 20;
383 
384   // First serialize all the 64-bit address vectors. We need to store all the
385   // offsets to later add to a wrapper table. We cannot serialize one vector and
386   // then add it to a table immediately, as it would violate the strict ordering
387   // of putting all 64-bit things at the tail of the buffer.
388   std::array<Offset64<Vector<int8_t>>, kNumVectors> offsets_64bit;
389   for (size_t i = 0; i < kNumVectors; ++i) {
390     offsets_64bit[i] = builder.CreateVector64<Vector>(data);
391   }
392 
393   // Create some unrelated, 64-bit offset value for later testing.
394   const Offset64<String> far_string_offset =
395       builder.CreateString<Offset64>("some far string");
396 
397   // Now place all the offsets into their own wrapper tables. Again, we have to
398   // store the offsets before we can add them to the root table vector.
399   std::array<Offset<WrapperTable>, kNumVectors> offsets_wrapper;
400   for (size_t i = 0; i < kNumVectors; ++i) {
401     offsets_wrapper[i] = CreateWrapperTable(builder, offsets_64bit[i]);
402   }
403 
404   // Now create the 32-bit vector that is stored in the root table.
405   // TODO(derekbailey): the array type wasn't auto deduced, see if that could be
406   // fixed.
407   const Offset<Vector<Offset<WrapperTable>>> many_vectors_offset =
408       builder.CreateVector<Offset<WrapperTable>>(offsets_wrapper);
409 
410   // Finish by building using the root table builder, to exercise a different
411   // code path than the other tests.
412   RootTableBuilder root_table_builder(builder);
413   root_table_builder.add_many_vectors(many_vectors_offset);
414   root_table_builder.add_far_string(far_string_offset);
415   const Offset<RootTable> root_table_offset = root_table_builder.Finish();
416 
417   // Finish the buffer.
418   FinishRootTableBuffer(builder, root_table_offset);
419 
420   Verifier::Options options;
421   // Allow the verifier to verify 64-bit buffers.
422   options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
423   options.assert = true;
424 
425   Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
426 
427   TEST_EQ(VerifyRootTableBuffer(verifier), true);
428 
429   const RootTable *root_table = GetRootTable(builder.GetBufferPointer());
430 
431   // Verify the fields.
432   TEST_EQ_STR(root_table->far_string()->c_str(), "some far string");
433   TEST_EQ(root_table->many_vectors()->size(), kNumVectors);
434 
435   // Spot check one of the vectors.
436   TEST_EQ(root_table->many_vectors()->Get(12)->vector()->size(), 20);
437   TEST_EQ(root_table->many_vectors()->Get(12)->vector()->Get(0), 42);
438   TEST_EQ(root_table->many_vectors()->Get(12)->vector()->Get(19), 18);
439 }
440 
Offset64ForceAlign()441 void Offset64ForceAlign() {
442   FlatBufferBuilder64 builder;
443 
444   // Setup some data to serialize that is less than the force_align size of 32
445   // bytes.
446   std::vector<uint8_t> data{ 1, 2, 3 };
447 
448   // Use the CreateDirect which calls the ForceVectorAlign
449   const auto root_table_offset =
450       CreateRootTableDirect(builder, nullptr, 0, nullptr, nullptr, nullptr,
451                             nullptr, nullptr, nullptr, nullptr, &data);
452 
453   // Finish the buffer.
454   FinishRootTableBuffer(builder, root_table_offset);
455 }
456 
457 }  // namespace tests
458 }  // namespace flatbuffers
459