Coverage Report

Created: 2026-02-14 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/pw_protobuf/decoder_fuzzer.cc
Line
Count
Source
1
// Copyright 2022 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 <algorithm>
16
#include <cstddef>
17
#include <cstdint>
18
#include <cstring>
19
#include <vector>
20
21
#include "fuzz.h"
22
#include "pw_fuzzer/fuzzed_data_provider.h"
23
#include "pw_protobuf/stream_decoder.h"
24
#include "pw_span/span.h"
25
#include "pw_status/status.h"
26
#include "pw_status/status_with_size.h"
27
#include "pw_stream/memory_stream.h"
28
#include "pw_stream/stream.h"
29
30
namespace pw::protobuf::fuzz {
31
namespace {
32
33
void RecursiveFuzzedDecode(FuzzedDataProvider& provider,
34
                           StreamDecoder& decoder,
35
5.59k
                           uint32_t depth = 0) {
36
5.59k
  constexpr size_t kMaxRepeatedRead = 256;
37
5.59k
  constexpr size_t kMaxDepth = 3;
38
39
5.59k
  if (depth > kMaxDepth) {
40
771
    return;
41
771
  }
42
15.9k
  while (provider.remaining_bytes() != 0 && decoder.Next().ok()) {
43
12.7k
    FieldType field_type = provider.ConsumeEnum<FieldType>();
44
12.7k
    switch (field_type) {
45
414
      case kUint32:
46
414
        if (!decoder.ReadUint32().status().ok()) {
47
141
          return;
48
141
        }
49
273
        break;
50
412
      case kPackedUint32: {
51
412
        uint32_t packed[kMaxRepeatedRead] = {0};
52
412
        if (!decoder.ReadPackedUint32(packed).status().ok()) {
53
117
          return;
54
117
        }
55
412
      } break;
56
295
      case kUint64:
57
225
        if (!decoder.ReadUint64().status().ok()) {
58
24
          return;
59
24
        }
60
201
        break;
61
385
      case kPackedUint64: {
62
385
        uint64_t packed[kMaxRepeatedRead] = {0};
63
385
        if (!decoder.ReadPackedUint64(packed).status().ok()) {
64
69
          return;
65
69
        }
66
385
      } break;
67
471
      case kInt32:
68
471
        if (!decoder.ReadInt32().status().ok()) {
69
208
          return;
70
208
        }
71
263
        break;
72
304
      case kPackedInt32: {
73
304
        int32_t packed[kMaxRepeatedRead] = {0};
74
304
        if (!decoder.ReadPackedInt32(packed).status().ok()) {
75
39
          return;
76
39
        }
77
304
      } break;
78
265
      case kInt64:
79
223
        if (!decoder.ReadInt64().status().ok()) {
80
27
          return;
81
27
        }
82
196
        break;
83
341
      case kPackedInt64: {
84
341
        int64_t packed[kMaxRepeatedRead] = {0};
85
341
        if (!decoder.ReadPackedInt64(packed).status().ok()) {
86
59
          return;
87
59
        }
88
341
      } break;
89
420
      case kSint32:
90
420
        if (!decoder.ReadSint32().status().ok()) {
91
135
          return;
92
135
        }
93
285
        break;
94
520
      case kPackedSint32: {
95
520
        int32_t packed[kMaxRepeatedRead] = {0};
96
520
        if (!decoder.ReadPackedSint32(packed).status().ok()) {
97
117
          return;
98
117
        }
99
520
      } break;
100
403
      case kSint64:
101
267
        if (!decoder.ReadSint64().status().ok()) {
102
72
          return;
103
72
        }
104
195
        break;
105
321
      case kPackedSint64: {
106
321
        int64_t packed[kMaxRepeatedRead] = {0};
107
321
        if (!decoder.ReadPackedSint64(packed).status().ok()) {
108
33
          return;
109
33
        }
110
321
      } break;
111
381
      case kBool:
112
381
        if (!decoder.ReadBool().status().ok()) {
113
169
          return;
114
169
        }
115
212
        break;
116
437
      case kFixed32:
117
437
        if (!decoder.ReadFixed32().status().ok()) {
118
7
          return;
119
7
        }
120
430
        break;
121
430
      case kPackedFixed32: {
122
298
        uint32_t packed[kMaxRepeatedRead] = {0};
123
298
        if (!decoder.ReadPackedFixed32(packed).status().ok()) {
124
39
          return;
125
39
        }
126
298
      } break;
127
259
      case kFixed64:
128
205
        if (!decoder.ReadFixed64().status().ok()) {
129
5
          return;
130
5
        }
131
200
        break;
132
583
      case kPackedFixed64: {
133
583
        uint64_t packed[kMaxRepeatedRead] = {0};
134
583
        if (!decoder.ReadPackedFixed64(packed).status().ok()) {
135
45
          return;
136
45
        }
137
583
      } break;
138
538
      case kSfixed32:
139
234
        if (!decoder.ReadSfixed32().status().ok()) {
140
7
          return;
141
7
        }
142
227
        break;
143
301
      case kPackedSfixed32: {
144
301
        int32_t packed[kMaxRepeatedRead] = {0};
145
301
        if (!decoder.ReadPackedSfixed32(packed).status().ok()) {
146
32
          return;
147
32
        }
148
301
      } break;
149
269
      case kSfixed64:
150
209
        if (!decoder.ReadSfixed64().status().ok()) {
151
11
          return;
152
11
        }
153
198
        break;
154
313
      case kPackedSfixed64: {
155
313
        int64_t packed[kMaxRepeatedRead] = {0};
156
313
        if (!decoder.ReadPackedSfixed64(packed).status().ok()) {
157
44
          return;
158
44
        }
159
313
      } break;
160
343
      case kFloat:
161
343
        if (!decoder.ReadFloat().status().ok()) {
162
10
          return;
163
10
        }
164
333
        break;
165
333
      case kPackedFloat: {
166
331
        float packed[kMaxRepeatedRead] = {0};
167
331
        if (!decoder.ReadPackedFloat(packed).status().ok()) {
168
39
          return;
169
39
        }
170
331
      } break;
171
292
      case kDouble:
172
211
        if (!decoder.ReadDouble().status().ok()) {
173
6
          return;
174
6
        }
175
205
        break;
176
336
      case kPackedDouble: {
177
336
        double packed[kMaxRepeatedRead] = {0};
178
336
        if (!decoder.ReadPackedDouble(packed).status().ok()) {
179
57
          return;
180
57
        }
181
336
      } break;
182
633
      case kBytes: {
183
633
        std::byte bytes[kMaxRepeatedRead] = {std::byte{0}};
184
633
        if (!decoder.ReadBytes(bytes).status().ok()) {
185
69
          return;
186
69
        }
187
633
      } break;
188
564
      case kString: {
189
396
        char str[kMaxRepeatedRead] = {0};
190
396
        if (!decoder.ReadString(str).status().ok()) {
191
56
          return;
192
56
        }
193
396
      } break;
194
3.25k
      case kPush: {
195
3.25k
        StreamDecoder nested_decoder = decoder.GetNestedDecoder();
196
3.25k
        RecursiveFuzzedDecode(provider, nested_decoder, depth + 1);
197
3.25k
      } break;
198
0
      case kPop:
199
0
        if (depth > 0) {
200
          // Special "field". The marks the end of a nested message.
201
0
          return;
202
0
        }
203
12.7k
    }
204
12.7k
  }
205
4.82k
}
206
207
2.34k
void TestOneInput(FuzzedDataProvider& provider) {
208
2.34k
  constexpr size_t kMaxFuzzedProtoSize = 4096;
209
2.34k
  std::vector<std::byte> proto_message_data = provider.ConsumeBytes<std::byte>(
210
2.34k
      provider.ConsumeIntegralInRange<size_t>(0, kMaxFuzzedProtoSize));
211
2.34k
  stream::MemoryReader memory_reader(proto_message_data);
212
2.34k
  StreamDecoder decoder(memory_reader);
213
2.34k
  RecursiveFuzzedDecode(provider, decoder);
214
2.34k
}
215
216
}  // namespace
217
}  // namespace pw::protobuf::fuzz
218
219
17.0k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
220
17.0k
  FuzzedDataProvider provider(data, size);
221
17.0k
  pw::protobuf::fuzz::TestOneInput(provider);
222
17.0k
  return 0;
223
17.0k
}