/proc/self/cwd/pw_protobuf/encoder_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2019 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 | | #include <cstddef> |
16 | | #include <cstdint> |
17 | | #include <cstring> |
18 | | #include <vector> |
19 | | |
20 | | #include "fuzz.h" |
21 | | #include "pw_fuzzer/asan_interface.h" |
22 | | #include "pw_fuzzer/fuzzed_data_provider.h" |
23 | | #include "pw_protobuf/encoder.h" |
24 | | #include "pw_span/span.h" |
25 | | |
26 | | namespace pw::protobuf::fuzz { |
27 | | namespace { |
28 | | |
29 | | // TODO: b/235289495 - Move this to pw_fuzzer/fuzzed_data_provider.h |
30 | | |
31 | | // Uses the given |provider| to pick and return a number between 0 and the |
32 | | // maximum numbers of T that can be generated from the remaining input data. |
33 | | template <typename T> |
34 | 58.4k | size_t ConsumeSize(FuzzedDataProvider& provider) { |
35 | 58.4k | size_t max = provider.remaining_bytes() / sizeof(T); |
36 | 58.4k | return provider.ConsumeIntegralInRange<size_t>(0, max); |
37 | 58.4k | } encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<unsigned int>(FuzzedDataProvider&) Line | Count | Source | 34 | 3.31k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 3.31k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 3.31k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 3.31k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<unsigned long>(FuzzedDataProvider&) Line | Count | Source | 34 | 4.19k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 4.19k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 4.19k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 4.19k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<int>(FuzzedDataProvider&) Line | Count | Source | 34 | 4.01k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 4.01k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 4.01k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 4.01k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<long>(FuzzedDataProvider&) Line | Count | Source | 34 | 4.21k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 4.21k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 4.21k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 4.21k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<float>(FuzzedDataProvider&) Line | Count | Source | 34 | 2.11k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 2.11k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 2.11k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 2.11k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<double>(FuzzedDataProvider&) Line | Count | Source | 34 | 2.81k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 2.81k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 2.81k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 2.81k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<std::byte>(FuzzedDataProvider&) Line | Count | Source | 34 | 37.7k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 37.7k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 37.7k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 37.7k | } |
|
38 | | |
39 | | // Uses the given |provider| to generate several instances of T, store them in |
40 | | // |data|, and then return a span to them. It is the caller's responsbility |
41 | | // to ensure |data| remains in scope as long as the returned span. |
42 | | template <typename T> |
43 | 20.6k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { |
44 | 20.6k | size_t num = ConsumeSize<T>(provider); |
45 | 20.6k | size_t off = data->size(); |
46 | 20.6k | if (num == 0) { |
47 | 10.9k | return span<const T>(); |
48 | 10.9k | } |
49 | | |
50 | 9.74k | data->reserve(off + num); |
51 | 20.8M | for (size_t i = 0; i < num; ++i) { |
52 | 20.8M | if constexpr (std::is_floating_point<T>::value) { |
53 | 4.30M | data->push_back(provider.ConsumeFloatingPoint<T>()); |
54 | 16.5M | } else { |
55 | 16.5M | data->push_back(provider.ConsumeIntegral<T>()); |
56 | 16.5M | } |
57 | 20.8M | } |
58 | 9.74k | return span(&((*data)[off]), num); |
59 | 20.6k | } encoder_fuzzer.cc:pw::span<unsigned int const, 18446744073709551615ul> pw::protobuf::fuzz::(anonymous namespace)::ConsumeSpan<unsigned int>(FuzzedDataProvider&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*) Line | Count | Source | 43 | 3.31k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 3.31k | size_t num = ConsumeSize<T>(provider); | 45 | 3.31k | size_t off = data->size(); | 46 | 3.31k | if (num == 0) { | 47 | 1.46k | return span<const T>(); | 48 | 1.46k | } | 49 | | | 50 | 1.85k | data->reserve(off + num); | 51 | 4.69M | for (size_t i = 0; i < num; ++i) { | 52 | | if constexpr (std::is_floating_point<T>::value) { | 53 | | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 4.69M | } else { | 55 | 4.69M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 4.69M | } | 57 | 4.69M | } | 58 | 1.85k | return span(&((*data)[off]), num); | 59 | 3.31k | } |
encoder_fuzzer.cc:pw::span<unsigned long const, 18446744073709551615ul> pw::protobuf::fuzz::(anonymous namespace)::ConsumeSpan<unsigned long>(FuzzedDataProvider&, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*) Line | Count | Source | 43 | 4.19k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 4.19k | size_t num = ConsumeSize<T>(provider); | 45 | 4.19k | size_t off = data->size(); | 46 | 4.19k | if (num == 0) { | 47 | 2.23k | return span<const T>(); | 48 | 2.23k | } | 49 | | | 50 | 1.96k | data->reserve(off + num); | 51 | 4.03M | for (size_t i = 0; i < num; ++i) { | 52 | | if constexpr (std::is_floating_point<T>::value) { | 53 | | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 4.03M | } else { | 55 | 4.03M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 4.03M | } | 57 | 4.03M | } | 58 | 1.96k | return span(&((*data)[off]), num); | 59 | 4.19k | } |
encoder_fuzzer.cc:pw::span<int const, 18446744073709551615ul> pw::protobuf::fuzz::(anonymous namespace)::ConsumeSpan<int>(FuzzedDataProvider&, std::__1::vector<int, std::__1::allocator<int> >*) Line | Count | Source | 43 | 4.01k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 4.01k | size_t num = ConsumeSize<T>(provider); | 45 | 4.01k | size_t off = data->size(); | 46 | 4.01k | if (num == 0) { | 47 | 2.63k | return span<const T>(); | 48 | 2.63k | } | 49 | | | 50 | 1.38k | data->reserve(off + num); | 51 | 4.99M | for (size_t i = 0; i < num; ++i) { | 52 | | if constexpr (std::is_floating_point<T>::value) { | 53 | | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 4.98M | } else { | 55 | 4.98M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 4.98M | } | 57 | 4.98M | } | 58 | 1.38k | return span(&((*data)[off]), num); | 59 | 4.01k | } |
encoder_fuzzer.cc:pw::span<long const, 18446744073709551615ul> pw::protobuf::fuzz::(anonymous namespace)::ConsumeSpan<long>(FuzzedDataProvider&, std::__1::vector<long, std::__1::allocator<long> >*) Line | Count | Source | 43 | 4.21k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 4.21k | size_t num = ConsumeSize<T>(provider); | 45 | 4.21k | size_t off = data->size(); | 46 | 4.21k | if (num == 0) { | 47 | 2.38k | return span<const T>(); | 48 | 2.38k | } | 49 | | | 50 | 1.83k | data->reserve(off + num); | 51 | 2.78M | for (size_t i = 0; i < num; ++i) { | 52 | | if constexpr (std::is_floating_point<T>::value) { | 53 | | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 2.78M | } else { | 55 | 2.78M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 2.78M | } | 57 | 2.78M | } | 58 | 1.83k | return span(&((*data)[off]), num); | 59 | 4.21k | } |
encoder_fuzzer.cc:pw::span<float const, 18446744073709551615ul> pw::protobuf::fuzz::(anonymous namespace)::ConsumeSpan<float>(FuzzedDataProvider&, std::__1::vector<float, std::__1::allocator<float> >*) Line | Count | Source | 43 | 2.11k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 2.11k | size_t num = ConsumeSize<T>(provider); | 45 | 2.11k | size_t off = data->size(); | 46 | 2.11k | if (num == 0) { | 47 | 980 | return span<const T>(); | 48 | 980 | } | 49 | | | 50 | 1.13k | data->reserve(off + num); | 51 | 2.42M | for (size_t i = 0; i < num; ++i) { | 52 | 2.41M | if constexpr (std::is_floating_point<T>::value) { | 53 | 2.41M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | | } else { | 55 | | data->push_back(provider.ConsumeIntegral<T>()); | 56 | | } | 57 | 2.41M | } | 58 | 1.13k | return span(&((*data)[off]), num); | 59 | 2.11k | } |
encoder_fuzzer.cc:pw::span<double const, 18446744073709551615ul> pw::protobuf::fuzz::(anonymous namespace)::ConsumeSpan<double>(FuzzedDataProvider&, std::__1::vector<double, std::__1::allocator<double> >*) Line | Count | Source | 43 | 2.81k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 2.81k | size_t num = ConsumeSize<T>(provider); | 45 | 2.81k | size_t off = data->size(); | 46 | 2.81k | if (num == 0) { | 47 | 1.24k | return span<const T>(); | 48 | 1.24k | } | 49 | | | 50 | 1.57k | data->reserve(off + num); | 51 | 1.88M | for (size_t i = 0; i < num; ++i) { | 52 | 1.88M | if constexpr (std::is_floating_point<T>::value) { | 53 | 1.88M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | | } else { | 55 | | data->push_back(provider.ConsumeIntegral<T>()); | 56 | | } | 57 | 1.88M | } | 58 | 1.57k | return span(&((*data)[off]), num); | 59 | 2.81k | } |
|
60 | | |
61 | | // Uses the given |provider| to generate a string, store it in |data|, and |
62 | | // return a C-style representation. It is the caller's responsbility to |
63 | | // ensure |data| remains in scope as long as the returned char*. |
64 | | const char* ConsumeString(FuzzedDataProvider& provider, |
65 | 138k | std::vector<std::string>* data) { |
66 | 138k | size_t off = data->size(); |
67 | | // OSS-Fuzz's clang doesn't have the zero-parameter version of |
68 | | // ConsumeRandomLengthString yet. |
69 | 138k | size_t max_length = std::numeric_limits<size_t>::max(); |
70 | 138k | data->push_back(provider.ConsumeRandomLengthString(max_length)); |
71 | 138k | return (*data)[off].c_str(); |
72 | 138k | } |
73 | | |
74 | | // Uses the given |provider| to generate non-arithmetic bytes, store them in |
75 | | // |data|, and return a span to them. It is the caller's responsbility to |
76 | | // ensure |data| remains in scope as long as the returned span. |
77 | | span<const std::byte> ConsumeBytes(FuzzedDataProvider& provider, |
78 | 37.7k | std::vector<std::byte>* data) { |
79 | 37.7k | size_t num = ConsumeSize<std::byte>(provider); |
80 | 37.7k | auto added = provider.ConsumeBytes<std::byte>(num); |
81 | 37.7k | size_t off = data->size(); |
82 | 37.7k | num = added.size(); |
83 | 37.7k | data->insert(data->end(), added.begin(), added.end()); |
84 | | // It's possible nothing was added, and the vector was empty to begin with. |
85 | 37.7k | if (data->empty()) { |
86 | 4.25k | return span<const std::byte>(); |
87 | 4.25k | } |
88 | 33.5k | return span(&((*data)[off]), num); |
89 | 37.7k | } |
90 | | |
91 | | void RecursiveFuzzedEncode(FuzzedDataProvider& provider, |
92 | | StreamEncoder& encoder, |
93 | 24.7k | uint32_t depth = 0) { |
94 | 24.7k | constexpr size_t kMaxDepth = 256; |
95 | 24.7k | if (depth > kMaxDepth) { |
96 | 2.39k | return; |
97 | 2.39k | } |
98 | | |
99 | | // Storage for generated spans |
100 | 22.3k | std::vector<uint32_t> u32s; |
101 | 22.3k | std::vector<uint64_t> u64s; |
102 | 22.3k | std::vector<int32_t> s32s; |
103 | 22.3k | std::vector<int64_t> s64s; |
104 | 22.3k | std::vector<float> floats; |
105 | 22.3k | std::vector<double> doubles; |
106 | 22.3k | std::vector<std::string> strings; |
107 | 22.3k | std::vector<std::byte> bytes; |
108 | | |
109 | | // Consume the fuzzing input, using it to generate a sequence of fields to |
110 | | // encode. Both the uint32_t field IDs and the fields values are generated. |
111 | | // Don't try to detect errors, ensures pushes and pops are balanced, or |
112 | | // otherwise hold the interface correctly. Instead, fuzz the widest possbile |
113 | | // set of inputs to the encoder to ensure it doesn't misbehave. |
114 | 1.76M | while (provider.remaining_bytes() != 0) { |
115 | 1.74M | switch (provider.ConsumeEnum<FieldType>()) { |
116 | 970k | case kUint32: |
117 | 970k | encoder |
118 | 970k | .WriteUint32(provider.ConsumeIntegral<uint32_t>(), |
119 | 970k | provider.ConsumeIntegral<uint32_t>()) |
120 | 970k | .IgnoreError(); |
121 | 970k | break; |
122 | 2.48k | case kPackedUint32: |
123 | 2.48k | encoder |
124 | 2.48k | .WritePackedUint32(provider.ConsumeIntegral<uint32_t>(), |
125 | 2.48k | ConsumeSpan<uint32_t>(provider, &u32s)) |
126 | 2.48k | .IgnoreError(); |
127 | 2.48k | break; |
128 | 4.13k | case kUint64: |
129 | 4.13k | encoder |
130 | 4.13k | .WriteUint64(provider.ConsumeIntegral<uint32_t>(), |
131 | 4.13k | provider.ConsumeIntegral<uint64_t>()) |
132 | 4.13k | .IgnoreError(); |
133 | 4.13k | break; |
134 | 3.06k | case kPackedUint64: |
135 | 3.06k | encoder |
136 | 3.06k | .WritePackedUint64(provider.ConsumeIntegral<uint32_t>(), |
137 | 3.06k | ConsumeSpan<uint64_t>(provider, &u64s)) |
138 | 3.06k | .IgnoreError(); |
139 | 3.06k | break; |
140 | 71.6k | case kInt32: |
141 | 71.6k | encoder |
142 | 71.6k | .WriteInt32(provider.ConsumeIntegral<uint32_t>(), |
143 | 71.6k | provider.ConsumeIntegral<int32_t>()) |
144 | 71.6k | .IgnoreError(); |
145 | 71.6k | break; |
146 | 2.03k | case kPackedInt32: |
147 | 2.03k | encoder |
148 | 2.03k | .WritePackedInt32(provider.ConsumeIntegral<uint32_t>(), |
149 | 2.03k | ConsumeSpan<int32_t>(provider, &s32s)) |
150 | 2.03k | .IgnoreError(); |
151 | 2.03k | break; |
152 | 103k | case kInt64: |
153 | 103k | encoder |
154 | 103k | .WriteInt64(provider.ConsumeIntegral<uint32_t>(), |
155 | 103k | provider.ConsumeIntegral<int64_t>()) |
156 | 103k | .IgnoreError(); |
157 | 103k | break; |
158 | 1.52k | case kPackedInt64: |
159 | 1.52k | encoder |
160 | 1.52k | .WritePackedInt64(provider.ConsumeIntegral<uint32_t>(), |
161 | 1.52k | ConsumeSpan<int64_t>(provider, &s64s)) |
162 | 1.52k | .IgnoreError(); |
163 | 1.52k | break; |
164 | 3.64k | case kSint32: |
165 | 3.64k | encoder |
166 | 3.64k | .WriteSint32(provider.ConsumeIntegral<uint32_t>(), |
167 | 3.64k | provider.ConsumeIntegral<int32_t>()) |
168 | 3.64k | .IgnoreError(); |
169 | 3.64k | break; |
170 | 1.00k | case kPackedSint32: |
171 | 1.00k | encoder |
172 | 1.00k | .WritePackedSint32(provider.ConsumeIntegral<uint32_t>(), |
173 | 1.00k | ConsumeSpan<int32_t>(provider, &s32s)) |
174 | 1.00k | .IgnoreError(); |
175 | 1.00k | break; |
176 | 2.25k | case kSint64: |
177 | 2.25k | encoder |
178 | 2.25k | .WriteSint64(provider.ConsumeIntegral<uint32_t>(), |
179 | 2.25k | provider.ConsumeIntegral<int64_t>()) |
180 | 2.25k | .IgnoreError(); |
181 | 2.25k | break; |
182 | 1.43k | case kPackedSint64: |
183 | 1.43k | encoder |
184 | 1.43k | .WritePackedSint64(provider.ConsumeIntegral<uint32_t>(), |
185 | 1.43k | ConsumeSpan<int64_t>(provider, &s64s)) |
186 | 1.43k | .IgnoreError(); |
187 | 1.43k | break; |
188 | 61.4k | case kBool: |
189 | 61.4k | encoder |
190 | 61.4k | .WriteBool(provider.ConsumeIntegral<uint32_t>(), |
191 | 61.4k | provider.ConsumeBool()) |
192 | 61.4k | .IgnoreError(); |
193 | 61.4k | break; |
194 | 182k | case kFixed32: |
195 | 182k | encoder |
196 | 182k | .WriteFixed32(provider.ConsumeIntegral<uint32_t>(), |
197 | 182k | provider.ConsumeIntegral<uint32_t>()) |
198 | 182k | .IgnoreError(); |
199 | 182k | break; |
200 | 830 | case kPackedFixed32: |
201 | 830 | encoder |
202 | 830 | .WritePackedFixed32(provider.ConsumeIntegral<uint32_t>(), |
203 | 830 | ConsumeSpan<uint32_t>(provider, &u32s)) |
204 | 830 | .IgnoreError(); |
205 | 830 | break; |
206 | 1.70k | case kFixed64: |
207 | 1.70k | encoder |
208 | 1.70k | .WriteFixed64(provider.ConsumeIntegral<uint32_t>(), |
209 | 1.70k | provider.ConsumeIntegral<uint64_t>()) |
210 | 1.70k | .IgnoreError(); |
211 | 1.70k | break; |
212 | 1.13k | case kPackedFixed64: |
213 | 1.13k | encoder |
214 | 1.13k | .WritePackedFixed64(provider.ConsumeIntegral<uint32_t>(), |
215 | 1.13k | ConsumeSpan<uint64_t>(provider, &u64s)) |
216 | 1.13k | .IgnoreError(); |
217 | 1.13k | break; |
218 | 117k | case kSfixed32: |
219 | 117k | encoder |
220 | 117k | .WriteSfixed32(provider.ConsumeIntegral<uint32_t>(), |
221 | 117k | provider.ConsumeIntegral<int32_t>()) |
222 | 117k | .IgnoreError(); |
223 | 117k | break; |
224 | 965 | case kPackedSfixed32: |
225 | 965 | encoder |
226 | 965 | .WritePackedSfixed32(provider.ConsumeIntegral<uint32_t>(), |
227 | 965 | ConsumeSpan<int32_t>(provider, &s32s)) |
228 | 965 | .IgnoreError(); |
229 | 965 | break; |
230 | 1.87k | case kSfixed64: |
231 | 1.87k | encoder |
232 | 1.87k | .WriteSfixed64(provider.ConsumeIntegral<uint32_t>(), |
233 | 1.87k | provider.ConsumeIntegral<int64_t>()) |
234 | 1.87k | .IgnoreError(); |
235 | 1.87k | break; |
236 | 1.25k | case kPackedSfixed64: |
237 | 1.25k | encoder |
238 | 1.25k | .WritePackedSfixed64(provider.ConsumeIntegral<uint32_t>(), |
239 | 1.25k | ConsumeSpan<int64_t>(provider, &s64s)) |
240 | 1.25k | .IgnoreError(); |
241 | 1.25k | break; |
242 | 2.25k | case kFloat: |
243 | 2.25k | encoder |
244 | 2.25k | .WriteFloat(provider.ConsumeIntegral<uint32_t>(), |
245 | 2.25k | provider.ConsumeFloatingPoint<float>()) |
246 | 2.25k | .IgnoreError(); |
247 | 2.25k | break; |
248 | 2.11k | case kPackedFloat: |
249 | 2.11k | encoder |
250 | 2.11k | .WritePackedFloat(provider.ConsumeIntegral<uint32_t>(), |
251 | 2.11k | ConsumeSpan<float>(provider, &floats)) |
252 | 2.11k | .IgnoreError(); |
253 | 2.11k | break; |
254 | 1.75k | case kDouble: |
255 | 1.75k | encoder |
256 | 1.75k | .WriteDouble(provider.ConsumeIntegral<uint32_t>(), |
257 | 1.75k | provider.ConsumeFloatingPoint<double>()) |
258 | 1.75k | .IgnoreError(); |
259 | 1.75k | break; |
260 | 2.81k | case kPackedDouble: |
261 | 2.81k | encoder |
262 | 2.81k | .WritePackedDouble(provider.ConsumeIntegral<uint32_t>(), |
263 | 2.81k | ConsumeSpan<double>(provider, &doubles)) |
264 | 2.81k | .IgnoreError(); |
265 | 2.81k | break; |
266 | 37.7k | case kBytes: |
267 | 37.7k | encoder |
268 | 37.7k | .WriteBytes(provider.ConsumeIntegral<uint32_t>(), |
269 | 37.7k | ConsumeBytes(provider, &bytes)) |
270 | 37.7k | .IgnoreError(); |
271 | 37.7k | break; |
272 | 138k | case kString: |
273 | 138k | encoder |
274 | 138k | .WriteString(provider.ConsumeIntegral<uint32_t>(), |
275 | 138k | ConsumeString(provider, &strings)) |
276 | 138k | .IgnoreError(); |
277 | 138k | break; |
278 | 21.2k | case kPush: { |
279 | | // Special "field". The marks the start of a nested message. |
280 | 21.2k | StreamEncoder nested_encoder = |
281 | 21.2k | encoder.GetNestedEncoder(provider.ConsumeIntegral<uint32_t>()); |
282 | 21.2k | RecursiveFuzzedEncode(provider, nested_encoder, depth + 1); |
283 | 21.2k | break; |
284 | 0 | } |
285 | 0 | case kPop: |
286 | 0 | if (depth > 0) { |
287 | | // Special "field". The marks the end of a nested message. |
288 | 0 | return; |
289 | 0 | } |
290 | 1.74M | } |
291 | 1.74M | } |
292 | 22.3k | } |
293 | | |
294 | 3.52k | void TestOneInput(FuzzedDataProvider& provider) { |
295 | 3.52k | static std::byte buffer[65536]; |
296 | | |
297 | | // Pick a subset of the buffer that the fuzzer is allowed to use, and poison |
298 | | // the rest. |
299 | 3.52k | size_t unpoisoned_length = |
300 | 3.52k | provider.ConsumeIntegralInRange<size_t>(0, sizeof(buffer)); |
301 | 3.52k | ByteSpan unpoisoned(buffer, unpoisoned_length); |
302 | 3.52k | void* poisoned = &buffer[unpoisoned_length]; |
303 | 3.52k | size_t poisoned_length = sizeof(buffer) - unpoisoned_length; |
304 | 3.52k | ASAN_POISON_MEMORY_REGION(poisoned, poisoned_length); |
305 | | |
306 | 3.52k | pw::protobuf::MemoryEncoder encoder(unpoisoned); |
307 | 3.52k | RecursiveFuzzedEncode(provider, encoder); |
308 | | |
309 | | // Don't forget to unpoison for the next iteration! |
310 | 3.52k | ASAN_UNPOISON_MEMORY_REGION(poisoned, poisoned_length); |
311 | 3.52k | } |
312 | | |
313 | | } // namespace |
314 | | } // namespace pw::protobuf::fuzz |
315 | | |
316 | 17.1k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
317 | 17.1k | FuzzedDataProvider provider(data, size); |
318 | 17.1k | pw::protobuf::fuzz::TestOneInput(provider); |
319 | 17.1k | return 0; |
320 | 17.1k | } |