Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_protobuf / encoder_fuzzer.cc
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 <pw_fuzzer/asan_interface.h>
16 #include <pw_fuzzer/fuzzed_data_provider.h>
17
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstring>
21 #include <span>
22 #include <vector>
23
24 #include "pw_protobuf/encoder.h"
25
26 namespace {
27
28 // Encodable values. The fuzzer will iteratively choose different field types to
29 // generate and encode.
30 enum FieldType : uint8_t {
31   kEncodeAndClear = 0,
32   kUint32,
33   kPackedUint32,
34   kUint64,
35   kPackedUint64,
36   kInt32,
37   kPackedInt32,
38   kInt64,
39   kPackedInt64,
40   kSint32,
41   kPackedSint32,
42   kSint64,
43   kPackedSint64,
44   kBool,
45   kFixed32,
46   kPackedFixed32,
47   kFixed64,
48   kPackedFixed64,
49   kSfixed32,
50   kPackedSfixed32,
51   kSfixed64,
52   kPackedSfixed64,
53   kFloat,
54   kPackedFloat,
55   kDouble,
56   kPackedDouble,
57   kBytes,
58   kString,
59   kPush,
60   kPop,
61   kMaxValue = kPop,
62 };
63
64 // TODO(pwbug/181): Move this to pw_fuzzer/fuzzed_data_provider.h
65
66 // Uses the given |provider| to pick and return a number between 0 and the
67 // maximum numbers of T that can be generated from the remaining input data.
68 template <typename T>
69 size_t ConsumeSize(FuzzedDataProvider* provider) {
70   size_t max = provider->remaining_bytes() / sizeof(T);
71   return provider->ConsumeIntegralInRange<size_t>(0, max);
72 }
73
74 // Uses the given |provider| to generate several instances of T, store them in
75 // |data|, and then return a std::span to them. It is the caller's responsbility
76 // to ensure |data| remains in scope as long as the returned std::span.
77 template <typename T>
78 std::span<const T> ConsumeSpan(FuzzedDataProvider* provider,
79                                std::vector<T>* data) {
80   size_t num = ConsumeSize<T>(provider);
81   size_t off = data->size();
82   data->reserve(off + num);
83   for (size_t i = 0; i < num; ++i) {
84     if constexpr (std::is_floating_point<T>::value) {
85       data->push_back(provider->ConsumeFloatingPoint<T>());
86     } else {
87       data->push_back(provider->ConsumeIntegral<T>());
88     }
89   }
90   return std::span(&((*data)[off]), num);
91 }
92
93 // Uses the given |provider| to generate a string, store it in |data|, and
94 // return a C-style representation. It is the caller's responsbility to
95 // ensure |data| remains in scope as long as the returned char*.
96 const char* ConsumeString(FuzzedDataProvider* provider,
97                           std::vector<std::string>* data) {
98   size_t off = data->size();
99   // OSS-Fuzz's clang doesn't have the zero-parameter version of
100   // ConsumeRandomLengthString yet.
101   size_t max_length = std::numeric_limits<size_t>::max();
102   data->push_back(provider->ConsumeRandomLengthString(max_length));
103   return (*data)[off].c_str();
104 }
105
106 // Uses the given |provider| to generate non-arithmetic bytes, store them in
107 // |data|, and return a std::span to them. It is the caller's responsbility to
108 // ensure |data| remains in scope as long as the returned std::span.
109 std::span<const std::byte> ConsumeBytes(FuzzedDataProvider* provider,
110                                         std::vector<std::byte>* data) {
111   size_t num = ConsumeSize<std::byte>(provider);
112   auto added = provider->ConsumeBytes<std::byte>(num);
113   size_t off = data->size();
114   num = added.size();
115   data->insert(data->end(), added.begin(), added.end());
116   return std::span(&((*data)[off]), num);
117 }
118
119 }  // namespace
120
121 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
122   static std::byte buffer[65536];
123
124   FuzzedDataProvider provider(data, size);
125
126   // Pick a subset of the buffer that the fuzzer is allowed to use, and poison
127   // the rest.
128   size_t unpoisoned_length =
129       provider.ConsumeIntegralInRange<size_t>(0, sizeof(buffer));
130   std::span<std::byte> unpoisoned(buffer, unpoisoned_length);
131   void* poisoned = &buffer[unpoisoned_length];
132   size_t poisoned_length = sizeof(buffer) - unpoisoned_length;
133   ASAN_POISON_MEMORY_REGION(poisoned, poisoned_length);
134
135   pw::protobuf::NestedEncoder encoder(unpoisoned);
136
137   // Storage for generated spans
138   std::vector<uint32_t> u32s;
139   std::vector<uint64_t> u64s;
140   std::vector<int32_t> s32s;
141   std::vector<int64_t> s64s;
142   std::vector<float> floats;
143   std::vector<double> doubles;
144   std::vector<std::string> strings;
145   std::vector<std::byte> bytes;
146
147   // Consume the fuzzing input, using it to generate a sequence of fields to
148   // encode. Both the uint32_t field IDs and the fields values are generated.
149   // Don't try to detect errors, ensures pushes and pops are balanced, or
150   // otherwise hold the interface correctly. Instead, fuzz the widest possbile
151   // set of inputs to the encoder to ensure it doesn't misbehave.
152   while (provider.remaining_bytes() != 0) {
153     switch (provider.ConsumeEnum<FieldType>()) {
154       case kEncodeAndClear:
155         // Special "field". Encode all the fields so far and reset the encoder.
156         encoder.Encode();
157         encoder.Clear();
158         break;
159       case kUint32:
160         encoder.WriteUint32(provider.ConsumeIntegral<uint32_t>(),
161                             provider.ConsumeIntegral<uint32_t>());
162         break;
163       case kPackedUint32:
164         encoder.WritePackedUint32(provider.ConsumeIntegral<uint32_t>(),
165                                   ConsumeSpan<uint32_t>(&provider, &u32s));
166         break;
167       case kUint64:
168         encoder.WriteUint64(provider.ConsumeIntegral<uint32_t>(),
169                             provider.ConsumeIntegral<uint64_t>());
170         break;
171       case kPackedUint64:
172         encoder.WritePackedUint64(provider.ConsumeIntegral<uint32_t>(),
173                                   ConsumeSpan<uint64_t>(&provider, &u64s));
174         break;
175       case kInt32:
176         encoder.WriteInt32(provider.ConsumeIntegral<uint32_t>(),
177                            provider.ConsumeIntegral<int32_t>());
178         break;
179       case kPackedInt32:
180         encoder.WritePackedInt32(provider.ConsumeIntegral<uint32_t>(),
181                                  ConsumeSpan<int32_t>(&provider, &s32s));
182         break;
183       case kInt64:
184         encoder.WriteInt64(provider.ConsumeIntegral<uint32_t>(),
185                            provider.ConsumeIntegral<int64_t>());
186         break;
187       case kPackedInt64:
188         encoder.WritePackedInt64(provider.ConsumeIntegral<uint32_t>(),
189                                  ConsumeSpan<int64_t>(&provider, &s64s));
190         break;
191       case kSint32:
192         encoder.WriteSint32(provider.ConsumeIntegral<uint32_t>(),
193                             provider.ConsumeIntegral<int32_t>());
194         break;
195       case kPackedSint32:
196         encoder.WritePackedSint32(provider.ConsumeIntegral<uint32_t>(),
197                                   ConsumeSpan<int32_t>(&provider, &s32s));
198         break;
199       case kSint64:
200         encoder.WriteSint64(provider.ConsumeIntegral<uint32_t>(),
201                             provider.ConsumeIntegral<int64_t>());
202         break;
203       case kPackedSint64:
204         encoder.WritePackedSint64(provider.ConsumeIntegral<uint32_t>(),
205                                   ConsumeSpan<int64_t>(&provider, &s64s));
206         break;
207       case kBool:
208         encoder.WriteBool(provider.ConsumeIntegral<uint32_t>(),
209                           provider.ConsumeBool());
210         break;
211       case kFixed32:
212         encoder.WriteFixed32(provider.ConsumeIntegral<uint32_t>(),
213                              provider.ConsumeIntegral<uint32_t>());
214         break;
215       case kPackedFixed32:
216         encoder.WritePackedFixed32(provider.ConsumeIntegral<uint32_t>(),
217                                    ConsumeSpan<uint32_t>(&provider, &u32s));
218         break;
219       case kFixed64:
220         encoder.WriteFixed64(provider.ConsumeIntegral<uint32_t>(),
221                              provider.ConsumeIntegral<uint64_t>());
222         break;
223       case kPackedFixed64:
224         encoder.WritePackedFixed64(provider.ConsumeIntegral<uint32_t>(),
225                                    ConsumeSpan<uint64_t>(&provider, &u64s));
226         break;
227       case kSfixed32:
228         encoder.WriteSfixed32(provider.ConsumeIntegral<uint32_t>(),
229                               provider.ConsumeIntegral<int32_t>());
230         break;
231       case kPackedSfixed32:
232         encoder.WritePackedSfixed32(provider.ConsumeIntegral<uint32_t>(),
233                                     ConsumeSpan<int32_t>(&provider, &s32s));
234         break;
235       case kSfixed64:
236         encoder.WriteSfixed64(provider.ConsumeIntegral<uint32_t>(),
237                               provider.ConsumeIntegral<int64_t>());
238         break;
239       case kPackedSfixed64:
240         encoder.WritePackedSfixed64(provider.ConsumeIntegral<uint32_t>(),
241                                     ConsumeSpan<int64_t>(&provider, &s64s));
242         break;
243       case kFloat:
244         encoder.WriteFloat(provider.ConsumeIntegral<uint32_t>(),
245                            provider.ConsumeFloatingPoint<float>());
246         break;
247       case kPackedFloat:
248         encoder.WritePackedFloat(provider.ConsumeIntegral<uint32_t>(),
249                                  ConsumeSpan<float>(&provider, &floats));
250         break;
251       case kDouble:
252         encoder.WriteDouble(provider.ConsumeIntegral<uint32_t>(),
253                             provider.ConsumeFloatingPoint<double>());
254         break;
255       case kPackedDouble:
256         encoder.WritePackedDouble(provider.ConsumeIntegral<uint32_t>(),
257                                   ConsumeSpan<double>(&provider, &doubles));
258         break;
259       case kBytes:
260         encoder.WriteBytes(provider.ConsumeIntegral<uint32_t>(),
261                            ConsumeBytes(&provider, &bytes));
262         break;
263       case kString:
264         encoder.WriteString(provider.ConsumeIntegral<uint32_t>(),
265                             ConsumeString(&provider, &strings));
266         break;
267       case kPush:
268         // Special "field". The marks the start of a nested message.
269         encoder.Push(provider.ConsumeIntegral<uint32_t>());
270         break;
271       case kPop:
272         // Special "field". this marks the end of a nested message. No attempt
273         // is made to match pushes to pops, in order to test that the encoder
274         // behaves correctly when they are mismatched.
275         encoder.Pop();
276         break;
277     }
278   }
279   // Ensure we call `Encode` at least once.
280   encoder.Encode();
281
282   // Don't forget to unpoison for the next iteration!
283   ASAN_UNPOISON_MEMORY_REGION(poisoned, poisoned_length);
284   return 0;
285 }