/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 | 70.4k | size_t ConsumeSize(FuzzedDataProvider& provider) { |
35 | 70.4k | size_t max = provider.remaining_bytes() / sizeof(T); |
36 | 70.4k | return provider.ConsumeIntegralInRange<size_t>(0, max); |
37 | 70.4k | } encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<unsigned int>(FuzzedDataProvider&) Line | Count | Source | 34 | 3.12k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 3.12k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 3.12k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 3.12k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<unsigned long>(FuzzedDataProvider&) Line | Count | Source | 34 | 3.67k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 3.67k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 3.67k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 3.67k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<int>(FuzzedDataProvider&) Line | Count | Source | 34 | 3.89k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 3.89k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 3.89k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 3.89k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<long>(FuzzedDataProvider&) Line | Count | Source | 34 | 3.96k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 3.96k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 3.96k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 3.96k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<float>(FuzzedDataProvider&) Line | Count | Source | 34 | 1.86k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 1.86k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 1.86k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 1.86k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<double>(FuzzedDataProvider&) Line | Count | Source | 34 | 2.08k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 2.08k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 2.08k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 2.08k | } |
encoder_fuzzer.cc:unsigned long pw::protobuf::fuzz::(anonymous namespace)::ConsumeSize<std::byte>(FuzzedDataProvider&) Line | Count | Source | 34 | 51.8k | size_t ConsumeSize(FuzzedDataProvider& provider) { | 35 | 51.8k | size_t max = provider.remaining_bytes() / sizeof(T); | 36 | 51.8k | return provider.ConsumeIntegralInRange<size_t>(0, max); | 37 | 51.8k | } |
|
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 | 18.6k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { |
44 | 18.6k | size_t num = ConsumeSize<T>(provider); |
45 | 18.6k | size_t off = data->size(); |
46 | 18.6k | if (num == 0) { |
47 | 10.0k | return span<const T>(); |
48 | 10.0k | } |
49 | | |
50 | 8.59k | data->reserve(off + num); |
51 | 18.2M | for (size_t i = 0; i < num; ++i) { |
52 | 18.2M | if constexpr (std::is_floating_point<T>::value) { |
53 | 14.7M | data->push_back(provider.ConsumeFloatingPoint<T>()); |
54 | 14.7M | } else { |
55 | 14.7M | data->push_back(provider.ConsumeIntegral<T>()); |
56 | 14.7M | } |
57 | 18.2M | } |
58 | 8.59k | return span(&((*data)[off]), num); |
59 | 18.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.12k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 3.12k | size_t num = ConsumeSize<T>(provider); | 45 | 3.12k | size_t off = data->size(); | 46 | 3.12k | if (num == 0) { | 47 | 1.41k | return span<const T>(); | 48 | 1.41k | } | 49 | | | 50 | 1.71k | data->reserve(off + num); | 51 | 4.63M | for (size_t i = 0; i < num; ++i) { | 52 | 4.63M | if constexpr (std::is_floating_point<T>::value) { | 53 | 4.63M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 4.63M | } else { | 55 | 4.63M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 4.63M | } | 57 | 4.63M | } | 58 | 1.71k | return span(&((*data)[off]), num); | 59 | 3.12k | } |
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 | 3.67k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 3.67k | size_t num = ConsumeSize<T>(provider); | 45 | 3.67k | size_t off = data->size(); | 46 | 3.67k | if (num == 0) { | 47 | 1.74k | return span<const T>(); | 48 | 1.74k | } | 49 | | | 50 | 1.93k | data->reserve(off + num); | 51 | 3.75M | for (size_t i = 0; i < num; ++i) { | 52 | 3.75M | if constexpr (std::is_floating_point<T>::value) { | 53 | 3.75M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 3.75M | } else { | 55 | 3.75M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 3.75M | } | 57 | 3.75M | } | 58 | 1.93k | return span(&((*data)[off]), num); | 59 | 3.67k | } |
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 | 3.89k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 3.89k | size_t num = ConsumeSize<T>(provider); | 45 | 3.89k | size_t off = data->size(); | 46 | 3.89k | if (num == 0) { | 47 | 2.62k | return span<const T>(); | 48 | 2.62k | } | 49 | | | 50 | 1.26k | data->reserve(off + num); | 51 | 4.02M | for (size_t i = 0; i < num; ++i) { | 52 | 4.01M | if constexpr (std::is_floating_point<T>::value) { | 53 | 4.01M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 4.01M | } else { | 55 | 4.01M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 4.01M | } | 57 | 4.01M | } | 58 | 1.26k | return span(&((*data)[off]), num); | 59 | 3.89k | } |
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 | 3.96k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 3.96k | size_t num = ConsumeSize<T>(provider); | 45 | 3.96k | size_t off = data->size(); | 46 | 3.96k | if (num == 0) { | 47 | 2.47k | return span<const T>(); | 48 | 2.47k | } | 49 | | | 50 | 1.49k | data->reserve(off + num); | 51 | 2.37M | for (size_t i = 0; i < num; ++i) { | 52 | 2.36M | if constexpr (std::is_floating_point<T>::value) { | 53 | 2.36M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 2.36M | } else { | 55 | 2.36M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 2.36M | } | 57 | 2.36M | } | 58 | 1.49k | return span(&((*data)[off]), num); | 59 | 3.96k | } |
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 | 1.86k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 1.86k | size_t num = ConsumeSize<T>(provider); | 45 | 1.86k | size_t off = data->size(); | 46 | 1.86k | if (num == 0) { | 47 | 901 | return span<const T>(); | 48 | 901 | } | 49 | | | 50 | 964 | data->reserve(off + num); | 51 | 1.81M | for (size_t i = 0; i < num; ++i) { | 52 | 1.81M | if constexpr (std::is_floating_point<T>::value) { | 53 | 1.81M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 1.81M | } else { | 55 | 1.81M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 1.81M | } | 57 | 1.81M | } | 58 | 964 | return span(&((*data)[off]), num); | 59 | 1.86k | } |
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.08k | span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) { | 44 | 2.08k | size_t num = ConsumeSize<T>(provider); | 45 | 2.08k | size_t off = data->size(); | 46 | 2.08k | if (num == 0) { | 47 | 866 | return span<const T>(); | 48 | 866 | } | 49 | | | 50 | 1.21k | data->reserve(off + num); | 51 | 1.67M | for (size_t i = 0; i < num; ++i) { | 52 | 1.67M | if constexpr (std::is_floating_point<T>::value) { | 53 | 1.67M | data->push_back(provider.ConsumeFloatingPoint<T>()); | 54 | 1.67M | } else { | 55 | 1.67M | data->push_back(provider.ConsumeIntegral<T>()); | 56 | 1.67M | } | 57 | 1.67M | } | 58 | 1.21k | return span(&((*data)[off]), num); | 59 | 2.08k | } |
|
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 | 135k | std::vector<std::string>* data) { |
66 | 135k | size_t off = data->size(); |
67 | | // OSS-Fuzz's clang doesn't have the zero-parameter version of |
68 | | // ConsumeRandomLengthString yet. |
69 | 135k | size_t max_length = std::numeric_limits<size_t>::max(); |
70 | 135k | data->push_back(provider.ConsumeRandomLengthString(max_length)); |
71 | 135k | return (*data)[off].c_str(); |
72 | 135k | } |
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 | 51.8k | std::vector<std::byte>* data) { |
79 | 51.8k | size_t num = ConsumeSize<std::byte>(provider); |
80 | 51.8k | auto added = provider.ConsumeBytes<std::byte>(num); |
81 | 51.8k | size_t off = data->size(); |
82 | 51.8k | num = added.size(); |
83 | 51.8k | data->insert(data->end(), added.begin(), added.end()); |
84 | | // It's possible nothing was added, and the vector was empty to begin with. |
85 | 51.8k | if (data->empty()) { |
86 | 6.17k | return span<const std::byte>(); |
87 | 6.17k | } |
88 | 45.6k | return span(&((*data)[off]), num); |
89 | 51.8k | } |
90 | | |
91 | | void RecursiveFuzzedEncode(FuzzedDataProvider& provider, |
92 | | StreamEncoder& encoder, |
93 | 21.0k | uint32_t depth = 0) { |
94 | 21.0k | constexpr size_t kMaxDepth = 256; |
95 | 21.0k | if (depth > kMaxDepth) { |
96 | 680 | return; |
97 | 680 | } |
98 | | |
99 | | // Storage for generated spans |
100 | 20.4k | std::vector<uint32_t> u32s; |
101 | 20.4k | std::vector<uint64_t> u64s; |
102 | 20.4k | std::vector<int32_t> s32s; |
103 | 20.4k | std::vector<int64_t> s64s; |
104 | 20.4k | std::vector<float> floats; |
105 | 20.4k | std::vector<double> doubles; |
106 | 20.4k | std::vector<std::string> strings; |
107 | 20.4k | 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.41M | while (provider.remaining_bytes() != 0) { |
115 | 1.39M | switch (provider.ConsumeEnum<FieldType>()) { |
116 | 780k | case kUint32: |
117 | 780k | encoder |
118 | 780k | .WriteUint32(provider.ConsumeIntegral<uint32_t>(), |
119 | 780k | provider.ConsumeIntegral<uint32_t>()) |
120 | 780k | .IgnoreError(); |
121 | 780k | break; |
122 | 2.35k | case kPackedUint32: |
123 | 2.35k | encoder |
124 | 2.35k | .WritePackedUint32(provider.ConsumeIntegral<uint32_t>(), |
125 | 2.35k | ConsumeSpan<uint32_t>(provider, &u32s)) |
126 | 2.35k | .IgnoreError(); |
127 | 2.35k | break; |
128 | 1.34k | case kUint64: |
129 | 1.34k | encoder |
130 | 1.34k | .WriteUint64(provider.ConsumeIntegral<uint32_t>(), |
131 | 1.34k | provider.ConsumeIntegral<uint64_t>()) |
132 | 1.34k | .IgnoreError(); |
133 | 1.34k | break; |
134 | 2.77k | case kPackedUint64: |
135 | 2.77k | encoder |
136 | 2.77k | .WritePackedUint64(provider.ConsumeIntegral<uint32_t>(), |
137 | 2.77k | ConsumeSpan<uint64_t>(provider, &u64s)) |
138 | 2.77k | .IgnoreError(); |
139 | 2.77k | break; |
140 | 70.9k | case kInt32: |
141 | 70.9k | encoder |
142 | 70.9k | .WriteInt32(provider.ConsumeIntegral<uint32_t>(), |
143 | 70.9k | provider.ConsumeIntegral<int32_t>()) |
144 | 70.9k | .IgnoreError(); |
145 | 70.9k | break; |
146 | 1.63k | case kPackedInt32: |
147 | 1.63k | encoder |
148 | 1.63k | .WritePackedInt32(provider.ConsumeIntegral<uint32_t>(), |
149 | 1.63k | ConsumeSpan<int32_t>(provider, &s32s)) |
150 | 1.63k | .IgnoreError(); |
151 | 1.63k | break; |
152 | 67.6k | case kInt64: |
153 | 67.6k | encoder |
154 | 67.6k | .WriteInt64(provider.ConsumeIntegral<uint32_t>(), |
155 | 67.6k | provider.ConsumeIntegral<int64_t>()) |
156 | 67.6k | .IgnoreError(); |
157 | 67.6k | break; |
158 | 1.44k | case kPackedInt64: |
159 | 1.44k | encoder |
160 | 1.44k | .WritePackedInt64(provider.ConsumeIntegral<uint32_t>(), |
161 | 1.44k | ConsumeSpan<int64_t>(provider, &s64s)) |
162 | 1.44k | .IgnoreError(); |
163 | 1.44k | break; |
164 | 3.15k | case kSint32: |
165 | 3.15k | encoder |
166 | 3.15k | .WriteSint32(provider.ConsumeIntegral<uint32_t>(), |
167 | 3.15k | provider.ConsumeIntegral<int32_t>()) |
168 | 3.15k | .IgnoreError(); |
169 | 3.15k | break; |
170 | 1.08k | case kPackedSint32: |
171 | 1.08k | encoder |
172 | 1.08k | .WritePackedSint32(provider.ConsumeIntegral<uint32_t>(), |
173 | 1.08k | ConsumeSpan<int32_t>(provider, &s32s)) |
174 | 1.08k | .IgnoreError(); |
175 | 1.08k | break; |
176 | 2.00k | case kSint64: |
177 | 2.00k | encoder |
178 | 2.00k | .WriteSint64(provider.ConsumeIntegral<uint32_t>(), |
179 | 2.00k | provider.ConsumeIntegral<int64_t>()) |
180 | 2.00k | .IgnoreError(); |
181 | 2.00k | break; |
182 | 1.53k | case kPackedSint64: |
183 | 1.53k | encoder |
184 | 1.53k | .WritePackedSint64(provider.ConsumeIntegral<uint32_t>(), |
185 | 1.53k | ConsumeSpan<int64_t>(provider, &s64s)) |
186 | 1.53k | .IgnoreError(); |
187 | 1.53k | break; |
188 | 16.3k | case kBool: |
189 | 16.3k | encoder |
190 | 16.3k | .WriteBool(provider.ConsumeIntegral<uint32_t>(), |
191 | 16.3k | provider.ConsumeBool()) |
192 | 16.3k | .IgnoreError(); |
193 | 16.3k | break; |
194 | 107k | case kFixed32: |
195 | 107k | encoder |
196 | 107k | .WriteFixed32(provider.ConsumeIntegral<uint32_t>(), |
197 | 107k | provider.ConsumeIntegral<uint32_t>()) |
198 | 107k | .IgnoreError(); |
199 | 107k | break; |
200 | 777 | case kPackedFixed32: |
201 | 777 | encoder |
202 | 777 | .WritePackedFixed32(provider.ConsumeIntegral<uint32_t>(), |
203 | 777 | ConsumeSpan<uint32_t>(provider, &u32s)) |
204 | 777 | .IgnoreError(); |
205 | 777 | break; |
206 | 1.53k | case kFixed64: |
207 | 1.53k | encoder |
208 | 1.53k | .WriteFixed64(provider.ConsumeIntegral<uint32_t>(), |
209 | 1.53k | provider.ConsumeIntegral<uint64_t>()) |
210 | 1.53k | .IgnoreError(); |
211 | 1.53k | break; |
212 | 905 | case kPackedFixed64: |
213 | 905 | encoder |
214 | 905 | .WritePackedFixed64(provider.ConsumeIntegral<uint32_t>(), |
215 | 905 | ConsumeSpan<uint64_t>(provider, &u64s)) |
216 | 905 | .IgnoreError(); |
217 | 905 | break; |
218 | 116k | case kSfixed32: |
219 | 116k | encoder |
220 | 116k | .WriteSfixed32(provider.ConsumeIntegral<uint32_t>(), |
221 | 116k | provider.ConsumeIntegral<int32_t>()) |
222 | 116k | .IgnoreError(); |
223 | 116k | break; |
224 | 1.17k | case kPackedSfixed32: |
225 | 1.17k | encoder |
226 | 1.17k | .WritePackedSfixed32(provider.ConsumeIntegral<uint32_t>(), |
227 | 1.17k | ConsumeSpan<int32_t>(provider, &s32s)) |
228 | 1.17k | .IgnoreError(); |
229 | 1.17k | break; |
230 | 1.17k | case kSfixed64: |
231 | 1.17k | encoder |
232 | 1.17k | .WriteSfixed64(provider.ConsumeIntegral<uint32_t>(), |
233 | 1.17k | provider.ConsumeIntegral<int64_t>()) |
234 | 1.17k | .IgnoreError(); |
235 | 1.17k | break; |
236 | 993 | case kPackedSfixed64: |
237 | 993 | encoder |
238 | 993 | .WritePackedSfixed64(provider.ConsumeIntegral<uint32_t>(), |
239 | 993 | ConsumeSpan<int64_t>(provider, &s64s)) |
240 | 993 | .IgnoreError(); |
241 | 993 | break; |
242 | 2.35k | case kFloat: |
243 | 2.35k | encoder |
244 | 2.35k | .WriteFloat(provider.ConsumeIntegral<uint32_t>(), |
245 | 2.35k | provider.ConsumeFloatingPoint<float>()) |
246 | 2.35k | .IgnoreError(); |
247 | 2.35k | break; |
248 | 1.86k | case kPackedFloat: |
249 | 1.86k | encoder |
250 | 1.86k | .WritePackedFloat(provider.ConsumeIntegral<uint32_t>(), |
251 | 1.86k | ConsumeSpan<float>(provider, &floats)) |
252 | 1.86k | .IgnoreError(); |
253 | 1.86k | break; |
254 | 1.56k | case kDouble: |
255 | 1.56k | encoder |
256 | 1.56k | .WriteDouble(provider.ConsumeIntegral<uint32_t>(), |
257 | 1.56k | provider.ConsumeFloatingPoint<double>()) |
258 | 1.56k | .IgnoreError(); |
259 | 1.56k | break; |
260 | 2.08k | case kPackedDouble: |
261 | 2.08k | encoder |
262 | 2.08k | .WritePackedDouble(provider.ConsumeIntegral<uint32_t>(), |
263 | 2.08k | ConsumeSpan<double>(provider, &doubles)) |
264 | 2.08k | .IgnoreError(); |
265 | 2.08k | break; |
266 | 51.8k | case kBytes: |
267 | 51.8k | encoder |
268 | 51.8k | .WriteBytes(provider.ConsumeIntegral<uint32_t>(), |
269 | 51.8k | ConsumeBytes(provider, &bytes)) |
270 | 51.8k | .IgnoreError(); |
271 | 51.8k | break; |
272 | 135k | case kString: |
273 | 135k | encoder |
274 | 135k | .WriteString(provider.ConsumeIntegral<uint32_t>(), |
275 | 135k | ConsumeString(provider, &strings)) |
276 | 135k | .IgnoreError(); |
277 | 135k | break; |
278 | 16.9k | case kPush: { |
279 | | // Special "field". The marks the start of a nested message. |
280 | 16.9k | StreamEncoder nested_encoder = |
281 | 16.9k | encoder.GetNestedEncoder(provider.ConsumeIntegral<uint32_t>()); |
282 | 16.9k | RecursiveFuzzedEncode(provider, nested_encoder, depth + 1); |
283 | 16.9k | 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.39M | } |
291 | 1.39M | } |
292 | 20.4k | } |
293 | | |
294 | 4.15k | void TestOneInput(FuzzedDataProvider& provider) { |
295 | 4.15k | 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 | 4.15k | size_t unpoisoned_length = |
300 | 4.15k | provider.ConsumeIntegralInRange<size_t>(0, sizeof(buffer)); |
301 | 4.15k | ByteSpan unpoisoned(buffer, unpoisoned_length); |
302 | 4.15k | void* poisoned = &buffer[unpoisoned_length]; |
303 | 4.15k | size_t poisoned_length = sizeof(buffer) - unpoisoned_length; |
304 | 4.15k | ASAN_POISON_MEMORY_REGION(poisoned, poisoned_length); |
305 | | |
306 | 4.15k | pw::protobuf::MemoryEncoder encoder(unpoisoned); |
307 | 4.15k | RecursiveFuzzedEncode(provider, encoder); |
308 | | |
309 | | // Don't forget to unpoison for the next iteration! |
310 | 4.15k | ASAN_UNPOISON_MEMORY_REGION(poisoned, poisoned_length); |
311 | 4.15k | } |
312 | | |
313 | | } // namespace |
314 | | } // namespace pw::protobuf::fuzz |
315 | | |
316 | 6.89k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
317 | 6.89k | FuzzedDataProvider provider(data, size); |
318 | 6.89k | pw::protobuf::fuzz::TestOneInput(provider); |
319 | 6.89k | return 0; |
320 | 6.89k | } |