/proc/self/cwd/pw_tokenizer/detokenize_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2020 The Pigweed Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
4 | | // use this file except in compliance with the License. You may obtain a copy of |
5 | | // the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
11 | | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
12 | | // License for the specific language governing permissions and limitations under |
13 | | // the License. |
14 | | |
15 | | // This file implements a basic fuzz test for the Detokenizer. |
16 | | // An instance of the Detokenizer is created from a minimal, nearly-empty token |
17 | | // database. Fuzz data is fed to the detokenizer in various supported input |
18 | | // argument formats at random, when then decodes this data and tries to match |
19 | | // it to tokens in the database. |
20 | | |
21 | | #include <cstddef> |
22 | | #include <cstdint> |
23 | | #include <cstring> |
24 | | #include <vector> |
25 | | |
26 | | #include "pw_fuzzer/fuzzed_data_provider.h" |
27 | | #include "pw_preprocessor/util.h" |
28 | | #include "pw_tokenizer/detokenize.h" |
29 | | |
30 | | namespace pw::tokenizer { |
31 | | namespace { |
32 | | |
33 | | constexpr size_t kFuzzRangeMin = 0; |
34 | | constexpr size_t kFuzzRangeMax = 10000; |
35 | | |
36 | | enum DetokenizeBufferArgumentType : uint8_t { |
37 | | kSpan = 0, |
38 | | kStringView, |
39 | | kPtrAndLength, |
40 | | kMaxValue = kPtrAndLength |
41 | | }; |
42 | | |
43 | | // In order to better fuzz the detokenizer, rather than use an empty token |
44 | | // database, we construct a minimal database with 4 entries out of a string |
45 | | // literal array that matches the token database format (see token_database.h |
46 | | // for detailed info on the database entry format) |
47 | | constexpr char kBasicData[] = |
48 | | "TOKENS\0\0" |
49 | | "\x04\x00\x00\x00" |
50 | | "\0\0\0\0" |
51 | | "\x01\x00\x00\x00----" |
52 | | "\x05\x00\x00\x00----" |
53 | | "\xFF\x00\x00\x00----" |
54 | | "\xFF\xEE\xEE\xDD----" |
55 | | "One\0" |
56 | | "TWO\0" |
57 | | "333\0" |
58 | | "FOUR"; |
59 | | |
60 | | } // namespace |
61 | | |
62 | 633 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
63 | 633 | static Detokenizer detokenizer(TokenDatabase::Create<kBasicData>()); |
64 | | |
65 | 633 | FuzzedDataProvider provider(data, size); |
66 | | |
67 | 17.3k | while (provider.remaining_bytes() != 0) { |
68 | | // Map the first word of the remaining fuzz data to a buffer argument |
69 | | // type, and feed the Detokenizer with a random length buffer to be |
70 | | // detokenized in the relevant format. The detokenized string returned |
71 | | // is itself of little consequence to this test. |
72 | 16.8k | switch (provider.ConsumeEnum<DetokenizeBufferArgumentType>()) { |
73 | 4.56k | case kSpan: { |
74 | 4.56k | size_t consumed_size = provider.ConsumeIntegralInRange<size_t>( |
75 | 4.56k | kFuzzRangeMin, kFuzzRangeMax); |
76 | 4.56k | std::vector<uint8_t> buffer = |
77 | 4.56k | provider.ConsumeBytes<uint8_t>(consumed_size); |
78 | 4.56k | if (buffer.empty()) { |
79 | 74 | return -1; |
80 | 74 | } |
81 | 4.49k | auto detokenized_string = |
82 | 4.49k | detokenizer.Detokenize(span(&buffer[0], buffer.size())); |
83 | 4.49k | static_cast<void>(detokenized_string); |
84 | 4.49k | break; |
85 | 4.56k | } |
86 | | |
87 | 5.05k | case kStringView: { |
88 | 5.05k | std::string str = |
89 | 5.05k | provider.ConsumeRandomLengthString(provider.remaining_bytes()); |
90 | 5.05k | auto detokenized_string = detokenizer.Detokenize(str); |
91 | 5.05k | static_cast<void>(detokenized_string); |
92 | 5.05k | break; |
93 | 4.56k | } |
94 | | |
95 | 7.20k | case kPtrAndLength: { |
96 | 7.20k | size_t consumed_size = provider.ConsumeIntegralInRange<size_t>( |
97 | 7.20k | kFuzzRangeMin, kFuzzRangeMax); |
98 | 7.20k | std::vector<uint8_t> buffer = |
99 | 7.20k | provider.ConsumeBytes<uint8_t>(consumed_size); |
100 | 7.20k | auto detokenized_string = |
101 | 7.20k | detokenizer.Detokenize(buffer.data(), buffer.size()); |
102 | 7.20k | static_cast<void>(detokenized_string); |
103 | 7.20k | break; |
104 | 4.56k | } |
105 | 16.8k | } |
106 | 16.8k | } |
107 | | |
108 | 559 | return 0; |
109 | 633 | } |
110 | | |
111 | | } // namespace pw::tokenizer |