Coverage Report

Created: 2026-07-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyaml_emitter_fuzzer.c
Line
Count
Source
1
// Copyright 2020 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://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,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "yaml.h"
16
#include "yaml_write_handler.h"
17
#include <assert.h>
18
#include <stdbool.h>
19
#include <stdint.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
24
#ifdef NDEBUG
25
#undef NDEBUG
26
#endif
27
28
516k
#define MAX_EVENTS 1024
29
30
291k
bool events_equal(yaml_event_t *event1, yaml_event_t *event2) {
31
  
32
291k
  const bool equal = true;
33
34
291k
  if (event1->type != event2->type)
35
2
    return equal;
36
37
291k
  switch (event1->type) {
38
1.80k
  case YAML_STREAM_START_EVENT:
39
1.80k
    return !equal;
40
41
12.2k
  case YAML_DOCUMENT_START_EVENT:
42
12.2k
    if ((event1->data.document_start.version_directive &&
43
1.35k
         !event2->data.document_start.version_directive) ||
44
12.2k
        (!event1->data.document_start.version_directive &&
45
10.8k
         event2->data.document_start.version_directive) ||
46
12.2k
        (event1->data.document_start.version_directive &&
47
1.35k
         event2->data.document_start.version_directive &&
48
1.35k
         (event1->data.document_start.version_directive->major !=
49
1.35k
              event2->data.document_start.version_directive->major ||
50
1.35k
          event1->data.document_start.version_directive->minor !=
51
1.35k
              event2->data.document_start.version_directive->minor)))
52
0
      return equal;
53
12.2k
    if ((event1->data.document_start.tag_directives.end -
54
12.2k
         event1->data.document_start.tag_directives.start) !=
55
12.2k
        (event2->data.document_start.tag_directives.end -
56
12.2k
         event2->data.document_start.tag_directives.start))
57
0
      return equal;
58
16.8k
    for (int k = 0; k < (event1->data.document_start.tag_directives.end -
59
16.8k
                         event1->data.document_start.tag_directives.start);
60
12.2k
         k++) {
61
4.57k
      if ((strcmp((char *)event1->data.document_start.tag_directives.start[k]
62
4.57k
                      .handle,
63
4.57k
                  (char *)event2->data.document_start.tag_directives.start[k]
64
4.57k
                      .handle) != 0) ||
65
4.57k
          (strcmp((char *)event1->data.document_start.tag_directives.start[k]
66
4.57k
                      .prefix,
67
4.57k
                  (char *)event2->data.document_start.tag_directives.start[k]
68
4.57k
                      .prefix) != 0))
69
0
        return equal;
70
4.57k
    }
71
12.2k
    return !equal;
72
73
12.1k
  case YAML_DOCUMENT_END_EVENT:
74
12.1k
    return !equal;
75
76
16
  case YAML_ALIAS_EVENT:
77
16
    return (strcmp((char *)event1->data.alias.anchor,
78
16
                   (char *)event2->data.alias.anchor) == 0);
79
80
83.6k
  case YAML_SCALAR_EVENT:
81
83.6k
    if ((event1->data.scalar.anchor && !event2->data.scalar.anchor) ||
82
83.6k
        (!event1->data.scalar.anchor && event2->data.scalar.anchor) ||
83
83.6k
        (event1->data.scalar.anchor && event2->data.scalar.anchor &&
84
1.51k
         strcmp((char *)event1->data.scalar.anchor,
85
1.51k
                (char *)event2->data.scalar.anchor) != 0))
86
0
      return equal;
87
83.6k
    if ((event1->data.scalar.tag && !event2->data.scalar.tag &&
88
251
         strcmp((char *)event1->data.scalar.tag, "!") != 0) ||
89
83.6k
        (!event1->data.scalar.tag && event2->data.scalar.tag &&
90
47.4k
         strcmp((char *)event2->data.scalar.tag, "!") != 0) ||
91
83.6k
        (event1->data.scalar.tag && event2->data.scalar.tag &&
92
2.08k
         strcmp((char *)event1->data.scalar.tag,
93
2.08k
                (char *)event2->data.scalar.tag) != 0))
94
19
      return equal;
95
83.6k
    if ((event1->data.scalar.length != event2->data.scalar.length) ||
96
83.6k
        memcmp(event1->data.scalar.value, event2->data.scalar.value,
97
83.6k
               event1->data.scalar.length) != 0)
98
5
      return equal;
99
83.6k
    if ((event1->data.scalar.plain_implicit !=
100
83.6k
         event2->data.scalar.plain_implicit) ||
101
83.6k
        (event1->data.scalar.quoted_implicit !=
102
83.6k
         event2->data.scalar.quoted_implicit))
103
26
      return equal;
104
83.6k
    return !equal;
105
106
46.6k
  case YAML_SEQUENCE_START_EVENT:
107
46.6k
    if ((event1->data.sequence_start.anchor &&
108
251
         !event2->data.sequence_start.anchor) ||
109
46.6k
        (!event1->data.sequence_start.anchor &&
110
46.4k
         event2->data.sequence_start.anchor) ||
111
46.6k
        (event1->data.sequence_start.anchor &&
112
251
         event2->data.sequence_start.anchor &&
113
251
         strcmp((char *)event1->data.sequence_start.anchor,
114
251
                (char *)event2->data.sequence_start.anchor) != 0))
115
0
      return equal;
116
46.6k
    if ((event1->data.sequence_start.tag && !event2->data.sequence_start.tag) ||
117
46.6k
        (!event1->data.sequence_start.tag && event2->data.sequence_start.tag) ||
118
46.6k
        (event1->data.sequence_start.tag && event2->data.sequence_start.tag &&
119
345
         strcmp((char *)event1->data.sequence_start.tag,
120
345
                (char *)event2->data.sequence_start.tag) != 0))
121
2
      return equal;
122
46.6k
    if ((event1->data.sequence_start.implicit !=
123
46.6k
         event2->data.sequence_start.implicit))
124
0
      return equal;
125
46.6k
    return !equal;
126
127
43.2k
  case YAML_MAPPING_START_EVENT:
128
43.2k
    if ((event1->data.mapping_start.anchor &&
129
371
         !event2->data.mapping_start.anchor) ||
130
43.2k
        (!event1->data.mapping_start.anchor &&
131
42.8k
         event2->data.mapping_start.anchor) ||
132
43.2k
        (event1->data.mapping_start.anchor &&
133
371
         event2->data.mapping_start.anchor &&
134
371
         strcmp((char *)event1->data.mapping_start.anchor,
135
371
                (char *)event2->data.mapping_start.anchor) != 0))
136
0
      return equal;
137
43.2k
    if ((event1->data.mapping_start.tag && !event2->data.mapping_start.tag) ||
138
43.2k
        (!event1->data.mapping_start.tag && event2->data.mapping_start.tag) ||
139
43.2k
        (event1->data.mapping_start.tag && event2->data.mapping_start.tag &&
140
411
         strcmp((char *)event1->data.mapping_start.tag,
141
411
                (char *)event2->data.mapping_start.tag) != 0))
142
2
      return equal;
143
43.2k
    if ((event1->data.mapping_start.implicit !=
144
43.2k
         event2->data.mapping_start.implicit))
145
0
      return equal;
146
43.2k
    return !equal;
147
148
91.2k
  default:
149
91.2k
    return !equal;
150
291k
  }
151
291k
}
152
153
516k
bool copy_event(yaml_event_t *event_to, yaml_event_t *event_from) {
154
155
516k
  switch (event_from->type) {
156
10.1k
  case YAML_STREAM_START_EVENT:
157
10.1k
    return yaml_stream_start_event_initialize(
158
10.1k
        event_to, event_from->data.stream_start.encoding);
159
160
1.98k
  case YAML_STREAM_END_EVENT:
161
1.98k
    return yaml_stream_end_event_initialize(event_to);
162
163
22.3k
  case YAML_DOCUMENT_START_EVENT:
164
22.3k
    return yaml_document_start_event_initialize(
165
22.3k
        event_to, event_from->data.document_start.version_directive,
166
22.3k
        event_from->data.document_start.tag_directives.start,
167
22.3k
        event_from->data.document_start.tag_directives.end,
168
22.3k
        event_from->data.document_start.implicit);
169
170
20.1k
  case YAML_DOCUMENT_END_EVENT:
171
20.1k
    return yaml_document_end_event_initialize(
172
20.1k
        event_to, event_from->data.document_end.implicit);
173
174
968
  case YAML_ALIAS_EVENT:
175
968
    return yaml_alias_event_initialize(event_to, event_from->data.alias.anchor);
176
177
163k
  case YAML_SCALAR_EVENT:
178
163k
    return yaml_scalar_event_initialize(
179
163k
        event_to, event_from->data.scalar.anchor, event_from->data.scalar.tag,
180
163k
        event_from->data.scalar.value, event_from->data.scalar.length,
181
163k
        event_from->data.scalar.plain_implicit,
182
163k
        event_from->data.scalar.quoted_implicit, event_from->data.scalar.style);
183
184
86.3k
  case YAML_SEQUENCE_START_EVENT:
185
86.3k
    return yaml_sequence_start_event_initialize(
186
86.3k
        event_to, event_from->data.sequence_start.anchor,
187
86.3k
        event_from->data.sequence_start.tag,
188
86.3k
        event_from->data.sequence_start.implicit,
189
86.3k
        event_from->data.sequence_start.style);
190
191
63.1k
  case YAML_SEQUENCE_END_EVENT:
192
63.1k
    return yaml_sequence_end_event_initialize(event_to);
193
194
92.2k
  case YAML_MAPPING_START_EVENT:
195
92.2k
    return yaml_mapping_start_event_initialize(
196
92.2k
        event_to, event_from->data.mapping_start.anchor,
197
92.2k
        event_from->data.mapping_start.tag,
198
92.2k
        event_from->data.mapping_start.implicit,
199
92.2k
        event_from->data.mapping_start.style);
200
201
55.4k
  case YAML_MAPPING_END_EVENT:
202
55.4k
    return yaml_mapping_end_event_initialize(event_to);
203
516k
  }
204
205
0
  return false;
206
516k
}
207
208
10.3k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
209
10.3k
  if (size < 2)
210
1
    return 0;
211
212
10.3k
  yaml_parser_t parser;
213
10.3k
  yaml_emitter_t emitter;
214
10.3k
  yaml_event_t event;
215
10.3k
  yaml_event_t events[MAX_EVENTS];
216
10.3k
  size_t event_number = 0;
217
10.3k
  bool done = false;
218
10.3k
  int count = 0;
219
10.3k
  bool is_canonical = data[0] & 1;
220
10.3k
  bool is_unicode = data[1] & 1;
221
10.3k
  data += 2;
222
10.3k
  size -= 2;
223
224
10.3k
  if (!yaml_parser_initialize(&parser))
225
0
    return 0;
226
227
10.3k
  yaml_parser_set_input_string(&parser, data, size);
228
10.3k
  if (!yaml_emitter_initialize(&emitter)) {
229
0
    yaml_parser_delete(&parser);
230
0
    return 0;
231
0
  }
232
233
10.3k
  yaml_emitter_set_canonical(&emitter, is_canonical);
234
10.3k
  yaml_emitter_set_unicode(&emitter, is_unicode);
235
236
10.3k
  yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0, /*capacity=*/1000};
237
10.3k
  yaml_emitter_set_output(&emitter, yaml_write_handler, &out);
238
239
522k
  while (!done) {
240
520k
    if (!yaml_parser_parse(&parser, &event)) {
241
4.26k
      goto delete_parser;
242
4.26k
    }
243
244
516k
    done = (event.type == YAML_STREAM_END_EVENT);
245
516k
    if (event_number >= MAX_EVENTS) {
246
19
      yaml_event_delete(&event);
247
19
      goto delete_parser;
248
19
    }
249
250
516k
    if (!copy_event(&events[event_number], &event)) {
251
46
      yaml_event_delete(&event);
252
46
      goto delete_parser;
253
46
    }
254
516k
    event_number++;
255
256
516k
    if (!yaml_emitter_emit(&emitter, &event)) {
257
4.03k
      goto delete_parser;
258
4.03k
    }
259
260
516k
  }
261
262
1.95k
  yaml_parser_delete(&parser);
263
264
1.95k
  if (!out.buf || out.size == 0)
265
154
    goto error;
266
267
1.80k
  done = false;
268
1.80k
  if (!yaml_parser_initialize(&parser))
269
0
    goto error;
270
271
1.80k
  yaml_parser_set_input_string(&parser, out.buf, out.size);
272
273
292k
  while (!done) {
274
291k
    if (!yaml_parser_parse(&parser, &event))
275
2
      break;
276
277
291k
    done = (event.type == YAML_STREAM_END_EVENT);
278
291k
    if (events_equal(events + count, &event)) {
279
72
      yaml_event_delete(&event);
280
72
      break;
281
72
    }
282
283
291k
    yaml_event_delete(&event);
284
291k
    count++;
285
291k
  }
286
287
10.1k
delete_parser:
288
289
10.1k
  yaml_parser_delete(&parser);
290
291
10.3k
error:
292
293
10.3k
  yaml_emitter_delete(&emitter);
294
295
526k
  for (int k = 0; k < event_number; k++) {
296
516k
    yaml_event_delete(events + k);
297
516k
  }
298
299
10.3k
  free(out.buf);
300
301
10.3k
  return 0;
302
10.1k
}