/src/flatbuffers/tests/fuzzer/flatbuffers_64bit_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <cstdint> |
2 | | #include <filesystem> |
3 | | #include <type_traits> |
4 | | |
5 | | #include "64bit/test_64bit_bfbs_generated.h" |
6 | | #include "64bit/test_64bit_generated.h" |
7 | | #include "flatbuffers/base.h" |
8 | | #include "flatbuffers/flatbuffer_builder.h" |
9 | | #include "flatbuffers/flatbuffers.h" |
10 | | #include "flatbuffers/reflection.h" |
11 | | #include "flatbuffers/verifier.h" |
12 | | #include "test_assert.h" |
13 | | #include "test_init.h" |
14 | | |
15 | | OneTimeTestInit OneTimeTestInit::one_time_init_; |
16 | | |
17 | | static RootTableBinarySchema schema; |
18 | | |
19 | | static constexpr uint8_t flags_sized_prefixed = 0b00000001; |
20 | | |
21 | | static const uint64_t kFnvPrime = 0x00000100000001b3ULL; |
22 | | static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL; |
23 | | |
24 | | namespace flatbuffers { |
25 | | |
26 | | template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>> |
27 | 7.57M | uint64_t Hash(T value, uint64_t hash) { |
28 | 7.57M | return (hash * kFnvPrime) ^ value; |
29 | 7.57M | } unsigned long flatbuffers::Hash<unsigned char, void>(unsigned char, unsigned long) Line | Count | Source | 27 | 7.39M | uint64_t Hash(T value, uint64_t hash) { | 28 | 7.39M | return (hash * kFnvPrime) ^ value; | 29 | 7.39M | } |
unsigned long flatbuffers::Hash<int, void>(int, unsigned long) Line | Count | Source | 27 | 176k | uint64_t Hash(T value, uint64_t hash) { | 28 | 176k | return (hash * kFnvPrime) ^ value; | 29 | 176k | } |
|
30 | | |
31 | 175k | uint64_t Hash(double value, uint64_t hash) { |
32 | 175k | static_assert(sizeof(double) == sizeof(uint64_t)); |
33 | 175k | return (hash * kFnvPrime) ^ static_cast<uint64_t>(value); |
34 | 175k | } |
35 | | |
36 | 1.56k | uint64_t Hash(const flatbuffers::String *value, uint64_t hash) { |
37 | 1.56k | if (value == nullptr) { return hash * kFnvPrime; } |
38 | 2.49M | for (auto &c : value->str()) { hash = Hash(static_cast<uint8_t>(c), hash); } |
39 | 486 | return hash; |
40 | 1.56k | } |
41 | | |
42 | 175k | uint64_t Hash(const LeafStruct *value, uint64_t hash) { |
43 | 175k | if (value == nullptr) { return hash * kFnvPrime; } |
44 | 175k | hash = Hash(value->a(), hash); |
45 | 175k | hash = Hash(value->b(), hash); |
46 | 175k | return hash; |
47 | 175k | } |
48 | | |
49 | 1.56k | template<typename T> uint64_t Hash(const Vector<T> *value, uint64_t hash) { |
50 | 1.56k | if (value == nullptr) { return hash * kFnvPrime; } |
51 | 1.61M | for (const T c : *value) { hash = Hash(c, hash); } |
52 | 337 | return hash; |
53 | 1.56k | } unsigned long flatbuffers::Hash<unsigned char>(flatbuffers::Vector<unsigned char, unsigned int> const*, unsigned long) Line | Count | Source | 49 | 782 | template<typename T> uint64_t Hash(const Vector<T> *value, uint64_t hash) { | 50 | 782 | if (value == nullptr) { return hash * kFnvPrime; } | 51 | 1.54M | for (const T c : *value) { hash = Hash(c, hash); } | 52 | 178 | return hash; | 53 | 782 | } |
unsigned long flatbuffers::Hash<LeafStruct const*>(flatbuffers::Vector<LeafStruct const*, unsigned int> const*, unsigned long) Line | Count | Source | 49 | 782 | template<typename T> uint64_t Hash(const Vector<T> *value, uint64_t hash) { | 50 | 782 | if (value == nullptr) { return hash * kFnvPrime; } | 51 | 71.3k | for (const T c : *value) { hash = Hash(c, hash); } | 52 | 159 | return hash; | 53 | 782 | } |
|
54 | | |
55 | 2.34k | template<typename T> uint64_t Hash(const Vector64<T> *value, uint64_t hash) { |
56 | 2.34k | if (value == nullptr) { return hash * kFnvPrime; } |
57 | 3.46M | for (const T c : *value) { hash = Hash(c, hash); } |
58 | 485 | return hash; |
59 | 2.34k | } unsigned long flatbuffers::Hash<unsigned char>(flatbuffers::Vector<unsigned char, unsigned long> const*, unsigned long) Line | Count | Source | 55 | 1.56k | template<typename T> uint64_t Hash(const Vector64<T> *value, uint64_t hash) { | 56 | 1.56k | if (value == nullptr) { return hash * kFnvPrime; } | 57 | 3.35M | for (const T c : *value) { hash = Hash(c, hash); } | 58 | 379 | return hash; | 59 | 1.56k | } |
unsigned long flatbuffers::Hash<LeafStruct const*>(flatbuffers::Vector<LeafStruct const*, unsigned long> const*, unsigned long) Line | Count | Source | 55 | 782 | template<typename T> uint64_t Hash(const Vector64<T> *value, uint64_t hash) { | 56 | 782 | if (value == nullptr) { return hash * kFnvPrime; } | 57 | 104k | for (const T c : *value) { hash = Hash(c, hash); } | 58 | 106 | return hash; | 59 | 782 | } |
|
60 | | |
61 | 1.25k | uint64_t Hash(const RootTable *value, uint64_t hash) { |
62 | 1.25k | if (value == nullptr) { return hash * kFnvPrime; } |
63 | | // Hash all the fields so we can exercise all parts of the code. |
64 | 782 | hash = Hash(value->far_vector(), hash); |
65 | 782 | hash = Hash(value->a(), hash); |
66 | 782 | hash = Hash(value->far_string(), hash); |
67 | 782 | hash = Hash(value->big_vector(), hash); |
68 | 782 | hash = Hash(value->near_string(), hash); |
69 | 782 | hash = Hash(value->nested_root(), hash); |
70 | 782 | hash = Hash(value->far_struct_vector(), hash); |
71 | 782 | hash = Hash(value->big_struct_vector(), hash); |
72 | 782 | return hash; |
73 | 1.25k | } |
74 | | |
75 | | static int AccessBuffer(const uint8_t *data, size_t size, |
76 | 625 | bool is_size_prefixed) { |
77 | 625 | const RootTable *root_table = |
78 | 625 | is_size_prefixed ? GetSizePrefixedRootTable(data) : GetRootTable(data); |
79 | 625 | TEST_NOTNULL(root_table); |
80 | | |
81 | 625 | uint64_t hash = kOffsetBasis; |
82 | 625 | hash = Hash(root_table, hash); |
83 | 625 | hash = Hash(root_table->nested_root_nested_root(), hash); |
84 | | |
85 | 625 | return 0; |
86 | 625 | } |
87 | | |
88 | 6 | extern "C" int LLVMFuzzerInitialize(int *, char ***argv) { |
89 | 6 | Verifier verifier(schema.begin(), schema.size()); |
90 | 6 | TEST_EQ(true, reflection::VerifySchemaBuffer(verifier)); |
91 | | |
92 | 6 | return 0; |
93 | 6 | } |
94 | | |
95 | 3.03k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
96 | 3.03k | if (size < FLATBUFFERS_MIN_BUFFER_SIZE) { return 0; } |
97 | | |
98 | | // Take the first bit of data as a flag to control things. |
99 | 3.03k | const uint8_t flags = data[0]; |
100 | 3.03k | data++; |
101 | 3.03k | size--; |
102 | | |
103 | 3.03k | Verifier::Options options; |
104 | 3.03k | options.assert = true; |
105 | 3.03k | options.check_alignment = true; |
106 | 3.03k | options.check_nested_flatbuffers = true; |
107 | | |
108 | 3.03k | Verifier verifier(data, size, options); |
109 | | |
110 | 3.03k | const bool is_size_prefixed = flags & flags_sized_prefixed; |
111 | | |
112 | | // Filter out data that isn't valid. |
113 | 3.03k | if ((is_size_prefixed && !VerifySizePrefixedRootTableBuffer(verifier)) || |
114 | 3.03k | !VerifyRootTableBuffer(verifier)) { |
115 | 2.40k | return 0; |
116 | 2.40k | } |
117 | | |
118 | 625 | return AccessBuffer(data, size, is_size_prefixed); |
119 | 3.03k | } |
120 | | |
121 | | } // namespace flatbuffers |