• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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