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 #define MAX_DOCUMENTS 16
29
nodes_equal(yaml_document_t * document1,int index1,yaml_document_t * document2,int index2,int level)30 bool nodes_equal(yaml_document_t *document1, int index1,
31 yaml_document_t *document2, int index2, int level) {
32 const bool equal = true;
33
34 if (level++ > 1000)
35 return !equal;
36 yaml_node_t *node1 = yaml_document_get_node(document1, index1);
37
38 if (!node1)
39 return !equal;
40
41 yaml_node_t *node2 = yaml_document_get_node(document2, index2);
42
43 if (!node2)
44 return !equal;
45
46 if (node1->type != node2->type)
47 return !equal;
48
49 if (strcmp((char *)node1->tag, (char *)node2->tag) != 0)
50 return !equal;
51
52 switch (node1->type) {
53 case YAML_SCALAR_NODE:
54 if (node1->data.scalar.length != node2->data.scalar.length)
55 return !equal;
56 if (strncmp((char *)node1->data.scalar.value,
57 (char *)node2->data.scalar.value,
58 node1->data.scalar.length) != 0)
59 return !equal;
60 break;
61 case YAML_SEQUENCE_NODE:
62 if ((node1->data.sequence.items.top - node1->data.sequence.items.start) !=
63 (node2->data.sequence.items.top - node2->data.sequence.items.start))
64 return !equal;
65 for (int k = 0; k < (node1->data.sequence.items.top -
66 node1->data.sequence.items.start);
67 k++) {
68 if (!nodes_equal(document1, node1->data.sequence.items.start[k],
69 document2, node2->data.sequence.items.start[k], level))
70 return !equal;
71 }
72 break;
73 case YAML_MAPPING_NODE:
74 if ((node1->data.mapping.pairs.top - node1->data.mapping.pairs.start) !=
75 (node2->data.mapping.pairs.top - node2->data.mapping.pairs.start))
76 return !equal;
77 for (int k = 0;
78 k < (node1->data.mapping.pairs.top - node1->data.mapping.pairs.start);
79 k++) {
80 if (!nodes_equal(document1, node1->data.mapping.pairs.start[k].key,
81 document2, node2->data.mapping.pairs.start[k].key,
82 level))
83 return !equal;
84 if (!nodes_equal(document1, node1->data.mapping.pairs.start[k].value,
85 document2, node2->data.mapping.pairs.start[k].value,
86 level))
87 return !equal;
88 }
89 break;
90 default:
91 return !equal;
92 }
93 return equal;
94 }
95
documents_equal(yaml_document_t * document1,yaml_document_t * document2)96 bool documents_equal(yaml_document_t *document1, yaml_document_t *document2) {
97
98 const bool equal = true;
99
100 if ((document1->version_directive && !document2->version_directive) ||
101 (!document1->version_directive && document2->version_directive) ||
102 (document1->version_directive && document2->version_directive &&
103 (document1->version_directive->major !=
104 document2->version_directive->major ||
105 document1->version_directive->minor !=
106 document2->version_directive->minor)))
107 return !equal;
108
109 if ((document1->tag_directives.end - document1->tag_directives.start) !=
110 (document2->tag_directives.end - document2->tag_directives.start))
111 return !equal;
112 for (int k = 0;
113 k < (document1->tag_directives.end - document1->tag_directives.start);
114 k++) {
115 if ((strcmp((char *)document1->tag_directives.start[k].handle,
116 (char *)document2->tag_directives.start[k].handle) != 0) ||
117 (strcmp((char *)document1->tag_directives.start[k].prefix,
118 (char *)document2->tag_directives.start[k].prefix) != 0))
119 return !equal;
120 }
121
122 if ((document1->nodes.top - document1->nodes.start) !=
123 (document2->nodes.top - document2->nodes.start))
124 return !equal;
125
126 if (document1->nodes.top != document1->nodes.start) {
127 if (!nodes_equal(document1, 1, document2, 1, 0))
128 return !equal;
129 }
130
131 return equal;
132 }
133
copy_document(yaml_document_t * document_to,yaml_document_t * document_from)134 bool copy_document(yaml_document_t *document_to,
135 yaml_document_t *document_from) {
136 bool error = true;
137
138 yaml_node_t *node;
139 yaml_node_item_t *item;
140 yaml_node_pair_t *pair;
141
142 if (!yaml_document_initialize(document_to, document_from->version_directive,
143 document_from->tag_directives.start,
144 document_from->tag_directives.end,
145 document_from->start_implicit,
146 document_from->end_implicit))
147 return !error;
148
149 for (node = document_from->nodes.start; node < document_from->nodes.top;
150 node++) {
151 switch (node->type) {
152 case YAML_SCALAR_NODE:
153 if (!yaml_document_add_scalar(
154 document_to, node->tag, node->data.scalar.value,
155 node->data.scalar.length, node->data.scalar.style))
156 goto out;
157 break;
158 case YAML_SEQUENCE_NODE:
159 if (!yaml_document_add_sequence(document_to, node->tag,
160 node->data.sequence.style))
161 goto out;
162 break;
163 case YAML_MAPPING_NODE:
164 if (!yaml_document_add_mapping(document_to, node->tag,
165 node->data.mapping.style))
166 goto out;
167 break;
168 default:
169 goto out;
170 }
171 }
172
173 for (node = document_from->nodes.start; node < document_from->nodes.top;
174 node++) {
175 switch (node->type) {
176 case YAML_SEQUENCE_NODE:
177 for (item = node->data.sequence.items.start;
178 item < node->data.sequence.items.top; item++) {
179 if (!yaml_document_append_sequence_item(
180 document_to, node - document_from->nodes.start + 1, *item))
181 goto out;
182 }
183 break;
184 case YAML_MAPPING_NODE:
185 for (pair = node->data.mapping.pairs.start;
186 pair < node->data.mapping.pairs.top; pair++) {
187 if (!yaml_document_append_mapping_pair(
188 document_to, node - document_from->nodes.start + 1, pair->key,
189 pair->value))
190 goto out;
191 }
192 break;
193 default:
194 break;
195 }
196 }
197 return error;
198
199 out:
200 yaml_document_delete(document_to);
201 return !error;
202 }
203
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)204 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
205 if (size < 2)
206 return 0;
207
208 yaml_parser_t parser;
209 yaml_emitter_t emitter;
210
211 yaml_document_t document;
212 yaml_document_t documents[MAX_DOCUMENTS];
213 size_t document_number = 0;
214 int count = 0;
215 bool done = false;
216 bool equal = false;
217 bool is_canonical = data[0] & 1;
218 bool is_unicode = data[1] & 1;
219 data += 2;
220 size -= 2;
221
222 if (!yaml_parser_initialize(&parser))
223 return 0;
224
225 yaml_parser_set_input_string(&parser, data, size);
226 if (!yaml_emitter_initialize(&emitter))
227 return 0;
228
229 yaml_emitter_set_canonical(&emitter, is_canonical);
230 yaml_emitter_set_unicode(&emitter, is_unicode);
231
232 yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0};
233 yaml_emitter_set_output(&emitter, yaml_write_handler, &out);
234 yaml_emitter_open(&emitter);
235
236 while (!done) {
237 if (!yaml_parser_load(&parser, &document)) {
238 equal = 1;
239 break;
240 }
241
242 done = (!yaml_document_get_root_node(&document));
243 if (!done) {
244 if (document_number >= MAX_DOCUMENTS) {
245 yaml_document_delete(&document);
246 equal = true;
247 break;
248 }
249
250 if (!copy_document(&documents[document_number++], &document)) {
251 yaml_document_delete(&document);
252 equal = true;
253 break;
254 }
255 if (!(yaml_emitter_dump(&emitter, &document) ||
256 (yaml_emitter_flush(&emitter) && 0))) {
257 equal = true;
258 break;
259 }
260
261 count++;
262 } else {
263 yaml_document_delete(&document);
264 }
265 }
266
267 yaml_parser_delete(&parser);
268 yaml_emitter_close(&emitter);
269 yaml_emitter_delete(&emitter);
270
271 if (!equal) {
272 count = 0;
273 done = false;
274 if (!yaml_parser_initialize(&parser))
275 goto error;
276
277 if (!out.buf) {
278 yaml_parser_delete(&parser);
279 goto error;
280 }
281
282 yaml_parser_set_input_string(&parser, out.buf, out.size);
283
284 while (!done) {
285 if (!yaml_parser_load(&parser, &document)) {
286 yaml_parser_delete(&parser);
287 goto error;
288 }
289
290 done = (!yaml_document_get_root_node(&document));
291 if (!done) {
292 if (!documents_equal(documents + count, &document)) {
293 yaml_parser_delete(&parser);
294 goto error;
295 }
296 count++;
297 }
298 yaml_document_delete(&document);
299 }
300 yaml_parser_delete(&parser);
301 }
302
303 for (int k = 0; k < document_number; k++) {
304 yaml_document_delete(documents + k);
305 }
306
307 error:
308
309 free(out.buf);
310 return 0;
311 }
312