1 /*
2 * api.c: a libFuzzer target to test node-related API functions.
3 *
4 * See Copyright for the status of this software.
5 *
6 * This is a simple virtual machine which runs fuzz data as a program.
7 * An important design goal is to execute as many API calls as possible
8 * per input byte.
9 *
10 * We use a fixed number of registers for basic types like integers
11 * or strings as well as libxml2 objects like xmlNode. The opcodes are
12 * single bytes which typically result in a call to an API function
13 * using the freshest registers for each argument type and storing the
14 * result in the stalest register. This can be implemented using a ring
15 * buffer.
16 *
17 * There are a few other opcodes to initialize or duplicate registers,
18 * so all kinds of API calls can potentially be generated from fuzz
19 * data.
20 *
21 * This architecture is similar to stack machine and benefits from
22 * great code density. The main difference is that values aren't
23 * destroyed when popping arguments from the stack and that the bottom
24 * of the stack is eventually overwritten if the ring buffer overflows.
25 *
26 * The main complication is memory management of nodes. Whenever a
27 * reference between two nodes is removed, whether by an API call or
28 * the VM clearing a register, we must check whether this leaves
29 * unreferenced nodes which can then be freed. There are no opcodes
30 * to free a node explicitly. The FIFO patterns generated by
31 * overflowing the ring buffer and freeing the registers at the end of
32 * a program seem to do a good enough job.
33 */
34
35 #include <stdlib.h>
36 #include <string.h>
37
38 #define XML_DEPRECATED
39
40 #include <libxml/catalog.h>
41 #include <libxml/HTMLtree.h>
42 #include <libxml/parser.h>
43 #include <libxml/tree.h>
44 #include <libxml/xmlerror.h>
45 #include "fuzz.h"
46
47 #if 0
48 #define DEBUG printf
49 #else
50 #define DEBUG(...)
51 #endif
52
53 #define MAX_CONTENT 100
54 #define MAX_COPY_NODES 50
55 #define MAX_COPY_OPS 20
56
57 typedef enum {
58 /* Basic operations */
59 OP_CREATE_INTEGER,
60 OP_CREATE_STRING,
61 OP_DUP_INTEGER,
62 OP_DUP_STRING,
63 OP_DUP_NODE,
64
65 /*** tree.h ***/
66
67 /* Tree constructors */
68 OP_XML_NEW_DOC,
69 OP_XML_NEW_NODE,
70 OP_XML_NEW_NODE_EAT_NAME,
71 OP_XML_NEW_DOC_NODE,
72 OP_XML_NEW_DOC_NODE_EAT_NAME,
73 OP_XML_NEW_DOC_RAW_NODE,
74 OP_XML_NEW_CHILD,
75 OP_XML_NEW_TEXT_CHILD,
76 OP_XML_NEW_PROP,
77 OP_XML_NEW_DOC_PROP,
78 OP_XML_NEW_NS_PROP,
79 OP_XML_NEW_NS_PROP_EAT_NAME,
80 OP_XML_NEW_TEXT,
81 OP_XML_NEW_TEXT_LEN,
82 OP_XML_NEW_DOC_TEXT,
83 OP_XML_NEW_DOC_TEXT_LEN,
84 OP_XML_NEW_PI,
85 OP_XML_NEW_DOC_PI,
86 OP_XML_NEW_COMMENT,
87 OP_XML_NEW_DOC_COMMENT,
88 OP_XML_NEW_CDATA_BLOCK,
89 OP_XML_NEW_CHAR_REF,
90 OP_XML_NEW_REFERENCE,
91 OP_XML_NEW_DOC_FRAGMENT,
92 OP_XML_CREATE_INT_SUBSET,
93 OP_XML_NEW_DTD,
94
95 /* Node copying */
96 OP_XML_COPY_DOC,
97 OP_XML_COPY_NODE,
98 OP_XML_COPY_NODE_LIST,
99 OP_XML_DOC_COPY_NODE,
100 OP_XML_DOC_COPY_NODE_LIST,
101 OP_XML_COPY_PROP,
102 OP_XML_COPY_PROP_LIST,
103 OP_XML_COPY_DTD,
104
105 /* Node accessors */
106 OP_NODE_PARENT,
107 OP_NODE_NEXT_SIBLING,
108 OP_NODE_PREV_SIBLING,
109 OP_NODE_FIRST_CHILD,
110 OP_XML_GET_LAST_CHILD,
111 OP_NODE_NAME,
112 OP_XML_NODE_SET_NAME,
113 OP_XML_NODE_GET_CONTENT,
114 OP_XML_NODE_SET_CONTENT,
115 OP_XML_NODE_SET_CONTENT_LEN,
116 OP_XML_NODE_ADD_CONTENT,
117 OP_XML_NODE_ADD_CONTENT_LEN,
118 OP_XML_GET_INT_SUBSET,
119 OP_XML_GET_LINE_NO,
120 OP_XML_GET_NODE_PATH,
121 OP_XML_DOC_GET_ROOT_ELEMENT,
122 OP_XML_DOC_SET_ROOT_ELEMENT,
123 OP_XML_NODE_IS_TEXT,
124 OP_XML_NODE_GET_ATTR_VALUE,
125 OP_XML_NODE_GET_LANG,
126 OP_XML_NODE_SET_LANG,
127 OP_XML_NODE_GET_SPACE_PRESERVE,
128 OP_XML_NODE_SET_SPACE_PRESERVE,
129 OP_XML_NODE_GET_BASE,
130 OP_XML_NODE_GET_BASE_SAFE,
131 OP_XML_NODE_SET_BASE,
132 OP_XML_IS_BLANK_NODE,
133
134 /* Attributes */
135 OP_XML_HAS_PROP,
136 OP_XML_HAS_NS_PROP,
137 OP_XML_GET_PROP,
138 OP_XML_GET_NS_PROP,
139 OP_XML_GET_NO_NS_PROP,
140 OP_XML_SET_PROP,
141 OP_XML_SET_NS_PROP,
142 OP_XML_REMOVE_PROP,
143 OP_XML_UNSET_PROP,
144 OP_XML_UNSET_NS_PROP,
145
146 /* Namespaces */
147 OP_XML_NEW_NS,
148 OP_XML_SEARCH_NS,
149 OP_XML_SEARCH_NS_BY_HREF,
150 OP_XML_GET_NS_LIST,
151 OP_XML_GET_NS_LIST_SAFE,
152 OP_XML_SET_NS,
153 OP_XML_COPY_NAMESPACE,
154 OP_XML_COPY_NAMESPACE_LIST,
155
156 /* Tree manipulation */
157 OP_XML_UNLINK_NODE,
158 OP_XML_ADD_CHILD,
159 OP_XML_ADD_CHILD_LIST,
160 OP_XML_REPLACE_NODE,
161 OP_XML_ADD_SIBLING,
162 OP_XML_ADD_PREV_SIBLING,
163 OP_XML_ADD_NEXT_SIBLING,
164
165 /* String output */
166 OP_XML_DOC_DUMP_MEMORY,
167 OP_XML_DOC_DUMP_MEMORY_ENC,
168 OP_XML_DOC_DUMP_FORMAT_MEMORY,
169 OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC,
170
171 /* FILE output, TODO, use fmemopen */
172 OP_XML_DOC_DUMP,
173 OP_XML_DOC_FORMAT_DUMP,
174 OP_XML_ELEM_DUMP,
175
176 /* xmlBuf output, TODO, no public API */
177 OP_XML_BUF_NODE_DUMP,
178 OP_XML_BUF_GET_NODE_CONTENT,
179
180 /* xmlBuffer output */
181 OP_XML_NODE_DUMP,
182 OP_XML_NODE_BUF_GET_CONTENT,
183 OP_XML_ATTR_SERIALIZE_TXT_CONTENT,
184 OP_XML_DUMP_ELEMENT_DECL,
185 OP_XML_DUMP_ELEMENT_TABLE,
186 OP_XML_DUMP_ATTRIBUTE_DECL,
187 OP_XML_DUMP_ATTRIBUTE_TABLE,
188 OP_XML_DUMP_NOTATION_DECL,
189 OP_XML_DUMP_NOTATION_TABLE,
190 OP_XML_DUMP_ENTITY_DECL,
191 OP_XML_DUMP_ENTITIES_TABLE,
192
193 /* xmlOutputBuffer */
194 OP_XML_SAVE_FILE_TO,
195 OP_XML_SAVE_FORMAT_FILE_TO,
196 OP_XML_NODE_DUMP_OUTPUT,
197
198 /* Misc */
199 OP_XML_TEXT_MERGE,
200 OP_XML_TEXT_CONCAT,
201 OP_XML_STRING_GET_NODE_LIST,
202 OP_XML_STRING_LEN_GET_NODE_LIST,
203 OP_XML_NODE_LIST_GET_STRING,
204 OP_XML_NODE_LIST_GET_RAW_STRING,
205 OP_XML_IS_XHTML,
206
207 /* DOM */
208 OP_XML_DOM_WRAP_RECONCILE_NAMESPACES,
209 OP_XML_DOM_WRAP_ADOPT_NODE,
210 OP_XML_DOM_WRAP_REMOVE_NODE,
211 OP_XML_DOM_WRAP_CLONE_NODE,
212 OP_XML_CHILD_ELEMENT_COUNT,
213 OP_XML_FIRST_ELEMENT_CHILD,
214 OP_XML_LAST_ELEMENT_CHILD,
215 OP_XML_NEXT_ELEMENT_SIBLING,
216 OP_XML_PREVIOUS_ELEMENT_SIBLING,
217
218 /*** parser.h ***/
219
220 OP_PARSE_DOCUMENT,
221
222 /*** valid.h ***/
223
224 OP_XML_ADD_ELEMENT_DECL,
225 OP_XML_ADD_ATTRIBUTE_DECL,
226 OP_XML_ADD_NOTATION_DECL,
227
228 OP_XML_GET_DTD_ELEMENT_DESC,
229 OP_XML_GET_DTD_QELEMENT_DESC,
230 OP_XML_GET_DTD_ATTR_DESC,
231 OP_XML_GET_DTD_QATTR_DESC,
232 OP_XML_GET_DTD_NOTATION_DESC,
233
234 OP_XML_ADD_ID,
235 OP_XML_ADD_ID_SAFE,
236 OP_XML_GET_ID,
237 OP_XML_IS_ID,
238 OP_XML_REMOVE_ID,
239
240 OP_XML_ADD_REF,
241 OP_XML_GET_REFS,
242 OP_XML_IS_REF,
243 OP_XML_REMOVE_REF,
244
245 OP_XML_IS_MIXED_ELEMENT,
246
247 OP_VALIDATE,
248 OP_XML_VALIDATE_ATTRIBUTE_VALUE,
249 OP_XML_VALIDATE_DTD,
250 OP_XML_VALIDATE_NOTATION_USE,
251
252 OP_XML_VALIDATE_NAME_VALUE,
253 OP_XML_VALIDATE_NAMES_VALUE,
254 OP_XML_VALIDATE_NMTOKEN_VALUE,
255 OP_XML_VALIDATE_NMTOKENS_VALUE,
256
257 OP_XML_VALID_NORMALIZE_ATTRIBUTE_VALUE,
258 OP_XML_VALID_CTXT_NORMALIZE_ATTRIBUTE_VALUE,
259 OP_XML_VALID_GET_POTENTIAL_CHILDREN,
260 OP_XML_VALID_GET_VALID_ELEMENTS,
261
262 /*** entities.h ***/
263
264 OP_XML_NEW_ENTITY,
265 OP_XML_ADD_ENTITY,
266 OP_XML_ADD_DOC_ENTITY,
267 OP_XML_ADD_DTD_ENTITY,
268
269 OP_XML_GET_PREDEFINED_ENTITY,
270 OP_XML_GET_DOC_ENTITY,
271 OP_XML_GET_DTD_ENTITY,
272 OP_XML_GET_PARAMETER_ENTITY,
273
274 OP_XML_ENCODE_ENTITIES_REENTRANT,
275 OP_XML_ENCODE_SPECIAL_CHARS,
276
277 /*** HTMLtree.h ***/
278
279 OP_HTML_NEW_DOC,
280 OP_HTML_NEW_DOC_NO_DTD,
281 OP_HTML_GET_META_ENCODING,
282 OP_HTML_SET_META_ENCODING,
283 OP_HTML_IS_BOOLEAN_ATTR,
284
285 OP_HTML_DOC_DUMP_MEMORY,
286 OP_HTML_DOC_DUMP_MEMORY_FORMAT,
287 OP_HTML_DOC_DUMP,
288 OP_HTML_NODE_DUMP_FILE,
289 OP_HTML_NODE_DUMP_FILE_FORMAT,
290 OP_HTML_NODE_DUMP,
291 OP_HTML_DOC_CONTENT_DUMP_OUTPUT,
292 OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT,
293 OP_HTML_NODE_DUMP_OUTPUT,
294 OP_HTML_NODE_DUMP_FORMAT_OUTPUT,
295
296 OP_MAX
297 } opType;
298
299 #define NODE_MASK_TEXT_CONTENT ( \
300 (1 << XML_TEXT_NODE) | \
301 (1 << XML_CDATA_SECTION_NODE) | \
302 (1 << XML_COMMENT_NODE) | \
303 (1 << XML_PI_NODE))
304
305 #define CHILD_MASK_DOCUMENT ( \
306 (1 << XML_ELEMENT_NODE) | \
307 (1 << XML_PI_NODE) | \
308 (1 << XML_COMMENT_NODE))
309
310 #define CHILD_MASK_CONTENT ( \
311 (1 << XML_ELEMENT_NODE) | \
312 (1 << XML_TEXT_NODE) | \
313 (1 << XML_CDATA_SECTION_NODE) | \
314 (1 << XML_ENTITY_REF_NODE) | \
315 (1 << XML_PI_NODE) | \
316 (1 << XML_COMMENT_NODE))
317
318 #define CHILD_MASK_ELEMENT ( \
319 CHILD_MASK_CONTENT | \
320 (1 << XML_ATTRIBUTE_NODE))
321
322 #define CHILD_MASK_ATTRIBUTE ( \
323 (1 << XML_TEXT_NODE) | \
324 (1 << XML_ENTITY_REF_NODE))
325
326 #define CHILD_MASK_DTD ( \
327 (1 << XML_ELEMENT_DECL) | \
328 (1 << XML_ATTRIBUTE_DECL) | \
329 (1 << XML_ENTITY_DECL))
330
331 static const int childMasks[] = {
332 0,
333 CHILD_MASK_ELEMENT, /* XML_ELEMENT_NODE */
334 CHILD_MASK_ATTRIBUTE, /* XML_ATTRIBUTE_NODE */
335 0, /* XML_TEXT_NODE */
336 0, /* XML_CDATA_SECTION_NODE */
337 0, /* XML_ENTITY_REF_NODE */
338 0, /* XML_ENTITY_NODE */
339 0, /* XML_PI_NODE */
340 0, /* XML_COMMENT_NODE */
341 CHILD_MASK_DOCUMENT, /* XML_DOCUMENT_NODE */
342 0, /* XML_DOCUMENT_TYPE_NODE */
343 CHILD_MASK_CONTENT, /* XML_DOCUMENT_FRAG_NODE */
344 0, /* XML_NOTATION_NODE */
345 CHILD_MASK_DOCUMENT, /* XML_HTML_DOCUMENT_NODE */
346 0, /* XML_DTD_NODE */
347 0, /* XML_ELEMENT_DECL */
348 0, /* XML_ATTRIBUTE_DECL */
349 0, /* XML_ENTITY_DECL */
350 0, /* XML_NAMESPACE_DECL */
351 0, /* XML_XINCLUDE_START */
352 0, /* XML_XINCLUDE_END */
353 CHILD_MASK_DOCUMENT /* XML_DOCB_DOCUMENT_NODE */
354 };
355
356 #define REG_MAX 8
357 #define REG_MASK (REG_MAX - 1)
358
359 typedef struct {
360 /* Indexes point beyond the most recent item */
361 int intIdx;
362 int stringIdx;
363 int nodeIdx;
364
365 int numCopyOps;
366
367 const char *opName;
368
369 /* Registers */
370 int integers[REG_MAX];
371 xmlChar *strings[REG_MAX];
372 xmlNodePtr nodes[REG_MAX];
373 } xmlFuzzApiVars;
374
375 static xmlFuzzApiVars varsStruct;
376 static xmlFuzzApiVars *const vars = &varsStruct;
377
378 /* Debug output */
379
380 static void
startOp(const char * name)381 startOp(const char *name) {
382 vars->opName = name;
383 DEBUG("%s(", name);
384 }
385
386 static void
endOp(void)387 endOp(void) {
388 DEBUG(" )\n");
389 }
390
391 /* Integers */
392
393 static int
getInt(int offset)394 getInt(int offset) {
395 int idx = (vars->intIdx - offset - 1) & REG_MASK;
396 DEBUG(" %d", vars->integers[idx]);
397 return vars->integers[idx];
398 }
399
400 static void
setInt(int offset,int n)401 setInt(int offset, int n) {
402 int idx = (vars->intIdx - offset - 1) & REG_MASK;
403 vars->integers[idx] = n;
404 }
405
406 static void
incIntIdx(void)407 incIntIdx(void) {
408 vars->intIdx = (vars->intIdx + 1) & REG_MASK;
409 }
410
411 /* Strings */
412
413 static const xmlChar *
getStr(int offset)414 getStr(int offset) {
415 int idx = (vars->stringIdx - offset - 1) & REG_MASK;
416 const xmlChar *str = vars->strings[idx];
417
418 if (str == NULL)
419 DEBUG(" NULL");
420 else
421 DEBUG(" \"%.20s\"", str);
422
423 return str;
424 }
425
426 static const char *
getCStr(int offset)427 getCStr(int offset) {
428 return (const char *) getStr(offset);
429 }
430
431 static void
setStr(int offset,xmlChar * str)432 setStr(int offset, xmlChar *str) {
433 xmlChar **strings = vars->strings;
434 int idx = (vars->stringIdx - offset - 1) & REG_MASK;
435 xmlChar *oldString = strings[idx];
436
437 strings[idx] = str;
438 if (oldString)
439 xmlFree(oldString);
440 }
441
442 static void
moveStr(int offset,xmlChar * str)443 moveStr(int offset, xmlChar *str) {
444 if (xmlStrlen(str) > 1000) {
445 setStr(offset, NULL);
446 xmlFree(str);
447 } else {
448 setStr(offset, str);
449 }
450 }
451
452 /*
453 * This doesn't use xmlMalloc and can't fail because of malloc failure
454 * injection.
455 */
456 static xmlChar *
uncheckedStrndup(const xmlChar * str,int size)457 uncheckedStrndup(const xmlChar *str, int size) {
458 xmlChar *copy;
459
460 if (str == NULL)
461 return NULL;
462
463 copy = BAD_CAST strndup((const char *) str, size);
464 if (copy == NULL) {
465 fprintf(stderr, "out of memory\n");
466 abort();
467 }
468
469 return copy;
470 }
471
472 static xmlChar *
uncheckedStrdup(const xmlChar * str)473 uncheckedStrdup(const xmlChar *str) {
474 return uncheckedStrndup(str, MAX_CONTENT);
475 }
476
477 static void
copyStr(int offset,const xmlChar * str)478 copyStr(int offset, const xmlChar *str) {
479 setStr(offset, uncheckedStrdup(str));
480 }
481
482 static void
incStrIdx(void)483 incStrIdx(void) {
484 vars->stringIdx = (vars->stringIdx + 1) & REG_MASK;
485 }
486
487 /* Nodes */
488
489 static void
490 dropNode(xmlNodePtr node);
491
492 static xmlNodePtr
getNode(int offset)493 getNode(int offset) {
494 int idx = (vars->nodeIdx - offset - 1) & REG_MASK;
495 if (vars->nodes[idx])
496 DEBUG(" n%d", idx);
497 else
498 DEBUG(" NULL");
499 fflush(stdout);
500 return vars->nodes[idx];
501 }
502
503 static xmlDocPtr
getDoc(int offset)504 getDoc(int offset) {
505 xmlNodePtr node = getNode(offset);
506
507 if (node == NULL)
508 return NULL;
509 return node->doc;
510 }
511
512 static xmlAttrPtr
getAttr(int offset)513 getAttr(int offset) {
514 xmlNodePtr node = getNode(offset);
515
516 if (node == NULL)
517 return NULL;
518 if (node->type == XML_ATTRIBUTE_NODE)
519 return (xmlAttrPtr) node;
520 if (node->type == XML_ELEMENT_NODE)
521 return node->properties;
522
523 return NULL;
524 }
525
526 static xmlDtdPtr
getDtd(int offset)527 getDtd(int offset) {
528 xmlNodePtr node = getNode(offset);
529 xmlDocPtr doc;
530
531 if (node == NULL)
532 return NULL;
533
534 if (node->type == XML_DTD_NODE)
535 return (xmlDtdPtr) node;
536
537 doc = node->doc;
538 if (doc == NULL)
539 return NULL;
540 if (doc->intSubset != NULL)
541 return doc->intSubset;
542 return doc->extSubset;
543 }
544
545 static void
setNode(int offset,xmlNodePtr node)546 setNode(int offset, xmlNodePtr node) {
547 int idx = (vars->nodeIdx - offset - 1) & REG_MASK;
548 xmlNodePtr oldNode = vars->nodes[idx];
549
550 if (node != oldNode) {
551 vars->nodes[idx] = node;
552 dropNode(oldNode);
553 }
554
555 if (node == NULL)
556 DEBUG(" ) /* NULL */\n");
557 else
558 DEBUG(" ) -> n%d\n", idx);
559 }
560
561 static void
incNodeIdx(void)562 incNodeIdx(void) {
563 xmlNodePtr oldNode;
564 int idx;
565
566 idx = vars->nodeIdx & REG_MASK;
567 vars->nodeIdx = (idx + 1) & REG_MASK;
568 oldNode = vars->nodes[idx];
569
570 if (oldNode != NULL) {
571 vars->nodes[idx] = NULL;
572 dropNode(oldNode);
573 }
574 }
575
576 static int
isValidChildType(xmlNodePtr parent,int childType)577 isValidChildType(xmlNodePtr parent, int childType) {
578 return ((1 << childType) & childMasks[parent->type]) != 0;
579 }
580
581 static int
isValidChild(xmlNodePtr parent,xmlNodePtr child)582 isValidChild(xmlNodePtr parent, xmlNodePtr child) {
583 xmlNodePtr cur;
584
585 if (child == NULL || parent == NULL)
586 return 1;
587
588 if (parent == child)
589 return 0;
590
591 if (((1 << child->type) & childMasks[parent->type]) == 0)
592 return 0;
593
594 if (child->children == NULL)
595 return 1;
596
597 for (cur = parent->parent; cur != NULL; cur = cur->parent)
598 if (cur == child)
599 return 0;
600
601 return 1;
602 }
603
604 static int
isTextContentNode(xmlNodePtr child)605 isTextContentNode(xmlNodePtr child) {
606 if (child == NULL)
607 return 0;
608
609 return ((1 << child->type) & NODE_MASK_TEXT_CONTENT) != 0;
610 }
611
612 static int
isDtdChild(xmlNodePtr child)613 isDtdChild(xmlNodePtr child) {
614 if (child == NULL)
615 return 0;
616
617 return ((1 << child->type) & CHILD_MASK_DTD) != 0;
618 }
619
620 static xmlNodePtr
nodeGetTree(xmlNodePtr node)621 nodeGetTree(xmlNodePtr node) {
622 xmlNodePtr cur = node;
623
624 while (cur->parent)
625 cur = cur->parent;
626 return cur;
627 }
628
629 /*
630 * This function is called whenever a reference to a node is removed.
631 * It checks whether the node is still reachable and frees unreferenced
632 * nodes.
633 *
634 * A node is reachable if its tree, identified by the root node,
635 * is reachable. If a non-document tree is unreachable, it can be
636 * freed.
637 *
638 * Multiple trees can share the same document, so a document tree
639 * can only be freed if no other trees reference the document.
640 */
641 static void
dropNode(xmlNodePtr node)642 dropNode(xmlNodePtr node) {
643 xmlNodePtr *nodes = vars->nodes;
644 xmlNodePtr tree;
645 xmlDocPtr doc;
646 int docReferenced = 0;
647 int i;
648
649 if (node == NULL)
650 return;
651
652 tree = nodeGetTree(node);
653 doc = node->doc;
654
655 for (i = 0; i < REG_MAX; i++) {
656 xmlNodePtr other;
657
658 other = nodes[i];
659 if (other == NULL)
660 continue;
661
662 /*
663 * Return if tree is referenced from another node
664 */
665 if (nodeGetTree(other) == tree)
666 return;
667 if (doc != NULL && other->doc == doc)
668 docReferenced = 1;
669 }
670
671 if (tree != (xmlNodePtr) doc && !isDtdChild(tree)) {
672 if (doc == NULL || tree->type != XML_DTD_NODE ||
673 ((xmlDtdPtr) tree != doc->intSubset &&
674 (xmlDtdPtr) tree != doc->extSubset))
675 xmlFreeNode(tree);
676 }
677
678 /*
679 * Also free document if it isn't referenced from other nodes
680 */
681 if (doc != NULL && !docReferenced)
682 xmlFreeDoc(doc);
683 }
684
685 /*
686 * removeNode and removeChildren remove all references to a node
687 * or its children from the registers. These functions should be
688 * called if an API function destroys nodes, for example by merging
689 * text nodes.
690 */
691
692 static void
removeNode(xmlNodePtr node)693 removeNode(xmlNodePtr node) {
694 int i;
695
696 for (i = 0; i < REG_MAX; i++)
697 if (vars->nodes[i] == node)
698 vars->nodes[i] = NULL;
699 }
700
701 static void
removeChildren(xmlNodePtr parent,int self)702 removeChildren(xmlNodePtr parent, int self) {
703 int i;
704
705 if (parent == NULL || (!self && parent->children == NULL))
706 return;
707
708 for (i = 0; i < REG_MAX; i++) {
709 xmlNodePtr node = vars->nodes[i];
710
711 if (node == parent) {
712 if (self)
713 vars->nodes[i] = NULL;
714 continue;
715 }
716
717 while (node != NULL) {
718 node = node->parent;
719 if (node == parent) {
720 vars->nodes[i] = NULL;
721 break;
722 }
723 }
724 }
725 }
726
727 static xmlNsPtr
nodeGetNs(xmlNodePtr node,int k)728 nodeGetNs(xmlNodePtr node, int k) {
729 int i = 0;
730 xmlNsPtr ns, next;
731
732 if (node == NULL || node->type != XML_ELEMENT_NODE)
733 return NULL;
734
735 ns = NULL;
736 next = node->nsDef;
737 while (1) {
738 while (next == NULL) {
739 node = node->parent;
740 if (node == NULL || node->type != XML_ELEMENT_NODE)
741 break;
742 next = node->nsDef;
743 }
744
745 if (next == NULL)
746 break;
747
748 ns = next;
749 if (i == k)
750 break;
751
752 next = ns->next;
753 i += 1;
754 }
755
756 return ns;
757 }
758
759 /*
760 * It's easy for programs to exhibit exponential growth patterns.
761 * For example, a tree being copied and added to the original source
762 * node doubles memory usage with two operations. Repeating these
763 * operations leads to 2^n nodes. Similar issues can arise when
764 * concatenating strings.
765 *
766 * We simply ignore tree copies or truncate text if they grow too
767 * large.
768 */
769
770 static void
checkContent(xmlNodePtr node)771 checkContent(xmlNodePtr node) {
772 if (node != NULL &&
773 (node->type == XML_TEXT_NODE ||
774 node->type == XML_CDATA_SECTION_NODE ||
775 node->type == XML_ENTITY_NODE ||
776 node->type == XML_PI_NODE ||
777 node->type == XML_COMMENT_NODE ||
778 node->type == XML_NOTATION_NODE) &&
779 xmlStrlen(node->content) > MAX_CONTENT) {
780 xmlNodeSetContent(node, NULL);
781 node->content = uncheckedStrdup(BAD_CAST "");
782 }
783 }
784
785 static int
countNodes(xmlNodePtr node)786 countNodes(xmlNodePtr node) {
787 xmlNodePtr cur;
788 int numNodes;
789
790 if (node == NULL)
791 return 0;
792
793 cur = node;
794 numNodes = 0;
795
796 while (1) {
797 numNodes += 1;
798
799 if (cur->children != NULL &&
800 cur->type != XML_ENTITY_REF_NODE) {
801 cur = cur->children;
802 } else {
803 while (cur->next == NULL) {
804 if (cur == node)
805 goto done;
806 cur = cur->parent;
807 }
808 cur = cur->next;
809 }
810 }
811
812 done:
813 return numNodes;
814 }
815
816 static xmlNodePtr
checkCopy(xmlNodePtr copy)817 checkCopy(xmlNodePtr copy) {
818 vars->numCopyOps += 1;
819
820 if (copy != NULL &&
821 (vars->numCopyOps > MAX_COPY_OPS ||
822 countNodes(copy) > MAX_COPY_NODES)) {
823 if (copy->type == XML_DOCUMENT_NODE ||
824 copy->type == XML_HTML_DOCUMENT_NODE)
825 xmlFreeDoc((xmlDocPtr) copy);
826 else
827 xmlFreeNode(copy);
828 copy = NULL;
829 }
830
831 return copy;
832 }
833
834 /*
835 * Fix namespaces, for example after unlinking a node. This makes
836 * sure that the node only references namespaces declared in ancestor
837 * nodes.
838 */
839 static int
fixNs(xmlNodePtr node)840 fixNs(xmlNodePtr node) {
841 if (node == NULL)
842 return 0;
843
844 if (node->type == XML_ELEMENT_NODE) {
845 return xmlReconciliateNs(node->doc, node);
846 } else if (node->type == XML_ATTRIBUTE_NODE) {
847 xmlNodePtr parent = node->parent;
848
849 if (parent != NULL)
850 return xmlReconciliateNs(parent->doc, parent);
851 else
852 node->ns = NULL;
853 }
854
855 return 0;
856 }
857
858 /* Node operations */
859
860 static void
opNodeAccessor(int op)861 opNodeAccessor(int op) {
862 xmlNodePtr node;
863
864 switch (op) {
865 case OP_NODE_PARENT:
866 startOp("parent"); break;
867 case OP_NODE_NEXT_SIBLING:
868 startOp("next"); break;
869 case OP_NODE_PREV_SIBLING:
870 startOp("prev"); break;
871 case OP_NODE_FIRST_CHILD:
872 startOp("children"); break;
873 case OP_XML_GET_LAST_CHILD:
874 startOp("xmlGetLastChild"); break;
875 case OP_XML_GET_INT_SUBSET:
876 startOp("xmlGetIntSubset"); break;
877 case OP_XML_DOC_GET_ROOT_ELEMENT:
878 startOp("xmlDocGetRootElement"); break;
879 default:
880 break;
881 }
882
883 incNodeIdx();
884 node = getNode(1);
885
886 if (node != NULL) {
887 switch (op) {
888 case OP_NODE_PARENT:
889 node = node->parent; break;
890 case OP_NODE_NEXT_SIBLING:
891 node = node->next; break;
892 case OP_NODE_PREV_SIBLING:
893 node = node->prev; break;
894 case OP_NODE_FIRST_CHILD:
895 node = node->children; break;
896 case OP_XML_GET_LAST_CHILD:
897 node = xmlGetLastChild(node); break;
898 case OP_XML_GET_INT_SUBSET:
899 node = (xmlNodePtr) xmlGetIntSubset(node->doc); break;
900 case OP_XML_DOC_GET_ROOT_ELEMENT:
901 node = xmlDocGetRootElement(node->doc); break;
902 default:
903 break;
904 }
905
906 /*
907 * Don't descend into predefined entities
908 */
909 if (node != NULL && node->type == XML_ENTITY_DECL) {
910 xmlEntityPtr ent = (xmlEntityPtr) node;
911
912 if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)
913 node = NULL;
914 }
915 }
916
917 setNode(0, node);
918 }
919
920 static void
opDup(int op)921 opDup(int op) {
922 int offset;
923
924 switch (op) {
925 case OP_DUP_INTEGER:
926 incIntIdx(); break;
927 case OP_DUP_STRING:
928 incStrIdx(); break;
929 case OP_DUP_NODE:
930 incNodeIdx(); break;
931 default:
932 break;
933 }
934
935 offset = (xmlFuzzReadInt(1) + 1) & REG_MASK;
936
937 if (offset != 0) {
938 startOp("dup");
939 switch (op) {
940 case OP_DUP_INTEGER:
941 setInt(0, getInt(offset));
942 endOp();
943 break;
944 case OP_DUP_STRING:
945 copyStr(0, getStr(offset));
946 endOp();
947 break;
948 case OP_DUP_NODE:
949 setNode(0, getNode(offset));
950 break;
951 default:
952 break;
953 }
954 }
955 }
956
957 int
LLVMFuzzerInitialize(int * argc ATTRIBUTE_UNUSED,char *** argv ATTRIBUTE_UNUSED)958 LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
959 char ***argv ATTRIBUTE_UNUSED) {
960 xmlFuzzMemSetup();
961 xmlInitParser();
962 #ifdef LIBXML_CATALOG_ENABLED
963 xmlInitializeCatalog();
964 xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
965 #endif
966 xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
967
968 return 0;
969 }
970
971 int
LLVMFuzzerTestOneInput(const char * data,size_t size)972 LLVMFuzzerTestOneInput(const char *data, size_t size) {
973 size_t maxAlloc;
974 int i;
975
976 if (size > 1000)
977 return 0;
978
979 memset(vars, 0, sizeof(*vars));
980
981 xmlFuzzDataInit(data, size);
982
983 maxAlloc = xmlFuzzReadInt(4) % (size * 50 + 10);
984 xmlFuzzMemSetLimit(maxAlloc);
985
986 /*
987 * Interpreter loop
988 *
989 * Processing an opcode typically involves
990 *
991 * - startOp for debugging
992 * - increase output register index if non-void
993 * - get arguments from input registers
994 * - invoke API function
995 * - set oomReport
996 * - set output register
997 * - memory management and other adjustments
998 * - endOp for void functions
999 */
1000
1001 while (xmlFuzzBytesRemaining()) {
1002 size_t readSize;
1003 int op = xmlFuzzReadInt(1);
1004 int oomReport = -1; /* -1 means unknown */
1005
1006 vars->opName = "[unset]";
1007
1008 switch (op) {
1009 case OP_CREATE_INTEGER:
1010 incIntIdx();
1011 setInt(0, (int) xmlFuzzReadInt(4));
1012 break;
1013
1014 case OP_CREATE_STRING:
1015 incStrIdx();
1016 copyStr(0, BAD_CAST xmlFuzzReadString(&readSize));
1017 break;
1018
1019 case OP_DUP_INTEGER:
1020 case OP_DUP_STRING:
1021 case OP_DUP_NODE:
1022 opDup(op);
1023 break;
1024
1025 case OP_PARSE_DOCUMENT:
1026 /*
1027 * We don't really want to test the parser but exposing
1028 * xmlReadDoc seems like a useful way generate or
1029 * round-trip documents.
1030 *
1031 * This also creates documents with a dictionary which
1032 * is crucial to hit some code paths.
1033 */
1034 startOp("xmlReadDoc");
1035 incNodeIdx();
1036 setNode(0, (xmlNodePtr) xmlReadDoc(
1037 getStr(0),
1038 getCStr(1),
1039 getCStr(2),
1040 getInt(0)));
1041 break;
1042
1043 case OP_XML_NEW_DOC: {
1044 xmlDocPtr doc;
1045
1046 /*
1047 * TODO: There's no public API function to generate a
1048 * document with a dictionary. We should add an extra
1049 * opcode that sets doc->dict.
1050 */
1051 startOp("xmlNewDoc");
1052 incNodeIdx();
1053 doc = xmlNewDoc(getStr(0));
1054 oomReport = (doc == NULL);
1055 setNode(0, (xmlNodePtr) doc);
1056 break;
1057 }
1058
1059 case OP_XML_NEW_NODE: {
1060 xmlNodePtr node;
1061 const xmlChar *name;
1062
1063 startOp("xmlNewNode");
1064 incNodeIdx();
1065 node = xmlNewNode(
1066 nodeGetNs(getNode(1), getInt(0)),
1067 name = getStr(0));
1068 oomReport = (name != NULL && node == NULL);
1069 if (fixNs(node) < 0)
1070 oomReport = 1;
1071 setNode(0, node);
1072 break;
1073 }
1074
1075 case OP_XML_NEW_NODE_EAT_NAME: {
1076 xmlNodePtr node;
1077 xmlChar *name;
1078
1079 startOp("xmlNewNodeEatName");
1080 incNodeIdx();
1081 node = xmlNewNodeEatName(
1082 nodeGetNs(getNode(1), getInt(0)),
1083 name = uncheckedStrdup(getStr(0)));
1084 oomReport = (name != NULL && node == NULL);
1085 if (fixNs(node) < 0)
1086 oomReport = 1;
1087 setNode(0, node);
1088 break;
1089 }
1090
1091 case OP_XML_NEW_DOC_NODE: {
1092 xmlNodePtr node;
1093 const xmlChar *name;
1094
1095 startOp("xmlNewDocNode");
1096 incNodeIdx();
1097 node = xmlNewDocNode(
1098 getDoc(1),
1099 nodeGetNs(getNode(2), getInt(0)),
1100 name = getStr(0),
1101 getStr(1));
1102 oomReport = (name != NULL && node == NULL);
1103 if (fixNs(node) < 0)
1104 oomReport = 1;
1105 setNode(0, node);
1106 break;
1107 }
1108
1109 case OP_XML_NEW_DOC_NODE_EAT_NAME: {
1110 xmlNodePtr node;
1111 xmlChar *name;
1112
1113 startOp("xmlNewDocNodeEatName");
1114 incNodeIdx();
1115 node = xmlNewDocNodeEatName(
1116 getDoc(1),
1117 nodeGetNs(getNode(2), getInt(0)),
1118 name = uncheckedStrdup(getStr(0)),
1119 getStr(1));
1120 oomReport = (name != NULL && node == NULL);
1121 if (fixNs(node) < 0)
1122 oomReport = 1;
1123 setNode(0, node);
1124 break;
1125 }
1126
1127 case OP_XML_NEW_DOC_RAW_NODE: {
1128 xmlNodePtr node;
1129 const xmlChar *name;
1130
1131 startOp("xmlNewDocRawNode");
1132 incNodeIdx();
1133 node = xmlNewDocRawNode(
1134 getDoc(1),
1135 nodeGetNs(getNode(2), getInt(0)),
1136 name = getStr(0),
1137 getStr(1));
1138 oomReport = (name != NULL && node == NULL);
1139 if (fixNs(node) < 0)
1140 oomReport = 1;
1141 setNode(0, node);
1142 break;
1143 }
1144
1145 case OP_XML_NEW_CHILD: {
1146 xmlNodePtr parent, node;
1147 const xmlChar *name;
1148
1149 startOp("xmlNewChild");
1150 incNodeIdx();
1151 /* Use parent namespace without fixup */
1152 node = xmlNewChild(
1153 parent = getNode(1),
1154 nodeGetNs(getNode(1), getInt(0)),
1155 name = getStr(0),
1156 getStr(1));
1157 oomReport =
1158 (parent != NULL &&
1159 isValidChildType(parent, XML_ELEMENT_NODE) &&
1160 name != NULL &&
1161 node == NULL);
1162 setNode(0, node);
1163 break;
1164 }
1165
1166 case OP_XML_NEW_TEXT_CHILD: {
1167 xmlNodePtr parent, node;
1168 const xmlChar *name;
1169
1170 startOp("xmlNewTextChild");
1171 incNodeIdx();
1172 /* Use parent namespace without fixup */
1173 node = xmlNewTextChild(
1174 parent = getNode(1),
1175 nodeGetNs(getNode(1), getInt(0)),
1176 name = getStr(0),
1177 getStr(1));
1178 oomReport =
1179 (parent != NULL &&
1180 isValidChildType(parent, XML_ELEMENT_NODE) &&
1181 name != NULL &&
1182 node == NULL);
1183 setNode(0, node);
1184 break;
1185 }
1186
1187 case OP_XML_NEW_PROP: {
1188 xmlNodePtr parent;
1189 xmlAttrPtr attr;
1190 const xmlChar *name;
1191
1192 startOp("xmlNewProp");
1193 incNodeIdx();
1194 attr = xmlNewProp(
1195 parent = getNode(1),
1196 name = getStr(0),
1197 getStr(1));
1198 oomReport =
1199 ((parent == NULL || parent->type == XML_ELEMENT_NODE) &&
1200 name != NULL &&
1201 attr == NULL);
1202 setNode(0, (xmlNodePtr) attr);
1203 break;
1204 }
1205
1206 case OP_XML_NEW_DOC_PROP: {
1207 xmlAttrPtr attr;
1208 const xmlChar *name;
1209
1210 startOp("xmlNewDocProp");
1211 incNodeIdx();
1212 attr = xmlNewDocProp(
1213 getDoc(1),
1214 name = getStr(0),
1215 getStr(1));
1216 oomReport = (name != NULL && attr == NULL);
1217 setNode(0, (xmlNodePtr) attr);
1218 break;
1219 }
1220
1221 case OP_XML_NEW_NS_PROP: {
1222 xmlAttrPtr attr;
1223
1224 startOp("xmlNewNsProp");
1225 incNodeIdx();
1226 attr = xmlNewNsProp(
1227 getNode(1),
1228 nodeGetNs(getNode(1), getInt(0)),
1229 getStr(0),
1230 getStr(1));
1231 /* xmlNewNsProp returns NULL on duplicate prefixes. */
1232 if (attr != NULL)
1233 oomReport = 0;
1234 setNode(0, (xmlNodePtr) attr);
1235 break;
1236 }
1237
1238 case OP_XML_NEW_NS_PROP_EAT_NAME: {
1239 xmlAttrPtr attr;
1240
1241 startOp("xmlNewNsPropEatName");
1242 incNodeIdx();
1243 attr = xmlNewNsPropEatName(
1244 getNode(1),
1245 nodeGetNs(getNode(1), getInt(0)),
1246 uncheckedStrdup(getStr(0)),
1247 getStr(1));
1248 if (attr != NULL)
1249 oomReport = 0;
1250 setNode(0, (xmlNodePtr) attr);
1251 break;
1252 }
1253
1254 case OP_XML_NEW_TEXT: {
1255 xmlNodePtr node;
1256
1257 startOp("xmlNewText");
1258 incNodeIdx();
1259 node = xmlNewText(getStr(0));
1260 oomReport = (node == NULL);
1261 setNode(0, node);
1262 break;
1263 }
1264
1265 case OP_XML_NEW_TEXT_LEN: {
1266 xmlNodePtr node;
1267 const xmlChar *text;
1268
1269 startOp("xmlNewTextLen");
1270 incNodeIdx();
1271 text = getStr(0);
1272 node = xmlNewTextLen(text, xmlStrlen(text));
1273 oomReport = (node == NULL);
1274 setNode(0, node);
1275 break;
1276 }
1277
1278 case OP_XML_NEW_DOC_TEXT: {
1279 xmlNodePtr node;
1280
1281 startOp("xmlNewDocText");
1282 incNodeIdx();
1283 node = xmlNewDocText(getDoc(1), getStr(0));
1284 oomReport = (node == NULL);
1285 setNode(0, node);
1286 break;
1287 }
1288
1289 case OP_XML_NEW_DOC_TEXT_LEN: {
1290 xmlDocPtr doc;
1291 xmlNodePtr node;
1292 const xmlChar *text;
1293
1294 startOp("xmlNewDocTextLen");
1295 incNodeIdx();
1296 doc = getDoc(1);
1297 text = getStr(0);
1298 node = xmlNewDocTextLen(doc, text, xmlStrlen(text));
1299 oomReport = (node == NULL);
1300 setNode(0, node);
1301 break;
1302 }
1303
1304 case OP_XML_NEW_PI: {
1305 xmlNodePtr node;
1306 const xmlChar *name;
1307
1308 startOp("xmlNewPI");
1309 incNodeIdx();
1310 node = xmlNewPI(
1311 name = getStr(0),
1312 getStr(1));
1313 oomReport = (name != NULL && node == NULL);
1314 setNode(0, node);
1315 break;
1316 }
1317
1318 case OP_XML_NEW_DOC_PI: {
1319 xmlNodePtr node;
1320 const xmlChar *name;
1321
1322 startOp("xmlNewDocPI");
1323 incNodeIdx();
1324 node = xmlNewDocPI(
1325 getDoc(1),
1326 name = getStr(0),
1327 getStr(1));
1328 oomReport = (name != NULL && node == NULL);
1329 setNode(0, node);
1330 break;
1331 }
1332
1333 case OP_XML_NEW_COMMENT: {
1334 xmlNodePtr node;
1335
1336 startOp("xmlNewComment");
1337 incNodeIdx();
1338 node = xmlNewComment(getStr(0));
1339 oomReport = (node == NULL);
1340 setNode(0, node);
1341 break;
1342 }
1343
1344 case OP_XML_NEW_DOC_COMMENT: {
1345 xmlNodePtr node;
1346
1347 startOp("xmlNewDocComment");
1348 incNodeIdx();
1349 node = xmlNewDocComment(
1350 getDoc(1),
1351 getStr(0));
1352 oomReport = (node == NULL);
1353 setNode(0, node);
1354 break;
1355 }
1356
1357 case OP_XML_NEW_CDATA_BLOCK: {
1358 xmlDocPtr doc;
1359 xmlNodePtr node;
1360 const xmlChar *text;
1361
1362 startOp("xmlNewCDataBlock");
1363 incNodeIdx();
1364 doc = getDoc(1);
1365 text = getStr(0);
1366 node = xmlNewDocTextLen(
1367 doc,
1368 text,
1369 xmlStrlen(text));
1370 oomReport = (node == NULL);
1371 setNode(0, node);
1372 break;
1373 }
1374
1375 case OP_XML_NEW_CHAR_REF: {
1376 xmlNodePtr node;
1377 const xmlChar *name;
1378
1379 startOp("xmlNewCharRef");
1380 incNodeIdx();
1381 node = xmlNewCharRef(
1382 getDoc(1),
1383 name = getStr(0));
1384 oomReport = (name != NULL && node == NULL);
1385 setNode(0, node);
1386 break;
1387 }
1388
1389 case OP_XML_NEW_REFERENCE: {
1390 xmlNodePtr node;
1391 const xmlChar *name;
1392
1393 startOp("xmlNewReference");
1394 incNodeIdx();
1395 node = xmlNewReference(
1396 getDoc(1),
1397 name = getStr(0));
1398 oomReport = (name != NULL && node == NULL);
1399 setNode(0, node);
1400 break;
1401 }
1402
1403 case OP_XML_NEW_DOC_FRAGMENT: {
1404 xmlNodePtr node;
1405
1406 startOp("xmlNewDocFragment");
1407 incNodeIdx();
1408 node = xmlNewDocFragment(getDoc(1));
1409 oomReport = (node == NULL);
1410 setNode(0, node);
1411 break;
1412 }
1413
1414 case OP_XML_CREATE_INT_SUBSET: {
1415 xmlDocPtr doc;
1416 xmlDtdPtr dtd = NULL;
1417
1418 startOp("xmlCreateIntSubset");
1419 incNodeIdx();
1420 doc = getDoc(1);
1421 if (doc == NULL || doc->intSubset == NULL) {
1422 dtd = xmlCreateIntSubset(
1423 doc,
1424 getStr(0),
1425 getStr(1),
1426 getStr(2));
1427 oomReport = (dtd == NULL);
1428 }
1429 setNode(0, (xmlNodePtr) dtd);
1430 break;
1431 }
1432
1433 case OP_XML_NEW_DTD: {
1434 xmlDocPtr doc;
1435 xmlDtdPtr dtd = NULL;
1436
1437 startOp("xmlNewDtd");
1438 incNodeIdx();
1439 doc = getDoc(1);
1440 if (doc == NULL || doc->extSubset == NULL) {
1441 dtd = xmlNewDtd(
1442 doc,
1443 getStr(0),
1444 getStr(1),
1445 getStr(2));
1446 oomReport = (dtd == NULL);
1447 }
1448 setNode(0, (xmlNodePtr) dtd);
1449 break;
1450 }
1451
1452 case OP_XML_COPY_DOC: {
1453 xmlDocPtr copy;
1454
1455 startOp("xmlCopyDoc");
1456 incNodeIdx();
1457 copy = xmlCopyDoc(
1458 getDoc(1),
1459 getInt(0));
1460 /*
1461 * TODO: Copying DTD nodes without a document can
1462 * result in an empty list.
1463 */
1464 if (copy != NULL)
1465 oomReport = 0;
1466 setNode(0, checkCopy((xmlNodePtr) copy));
1467 break;
1468 }
1469
1470 case OP_XML_COPY_NODE: {
1471 xmlNodePtr copy;
1472
1473 startOp("xmlCopyNode");
1474 incNodeIdx();
1475 copy = xmlCopyNode(
1476 getNode(1),
1477 getInt(0));
1478 if (copy != NULL)
1479 oomReport = 0;
1480 setNode(0, checkCopy((xmlNodePtr) copy));
1481 break;
1482 }
1483
1484 case OP_XML_COPY_NODE_LIST: {
1485 xmlNodePtr copy;
1486
1487 startOp("xmlCopyNodeList");
1488 copy = xmlCopyNodeList(getNode(0));
1489 if (copy != NULL)
1490 oomReport = 0;
1491 xmlFreeNodeList(copy);
1492 endOp();
1493 break;
1494 }
1495
1496 case OP_XML_DOC_COPY_NODE: {
1497 xmlNodePtr node, copy;
1498 xmlDocPtr doc;
1499
1500 startOp("xmlDocCopyNode");
1501 incNodeIdx();
1502 copy = xmlDocCopyNode(
1503 node = getNode(1),
1504 doc = getDoc(2),
1505 getInt(0));
1506 if (copy != NULL)
1507 oomReport = 0;
1508 setNode(0, checkCopy((xmlNodePtr) copy));
1509 break;
1510 }
1511
1512 case OP_XML_DOC_COPY_NODE_LIST: {
1513 xmlNodePtr copy;
1514
1515 startOp("xmlDocCopyNodeList");
1516 copy = xmlDocCopyNodeList(
1517 getDoc(0),
1518 getNode(1));
1519 if (copy != NULL)
1520 oomReport = 0;
1521 xmlFreeNodeList(copy);
1522 endOp();
1523 break;
1524 }
1525
1526 case OP_XML_COPY_PROP: {
1527 xmlAttrPtr copy;
1528
1529 startOp("xmlCopyProp");
1530 incNodeIdx();
1531 copy = xmlCopyProp(
1532 getNode(1),
1533 getAttr(2));
1534 /*
1535 * TODO: Copying attributes can result in an empty list
1536 * if there's a duplicate namespace prefix.
1537 */
1538 if (copy != NULL)
1539 oomReport = 0;
1540 if (copy != NULL) {
1541 /* Quirk */
1542 copy->parent = NULL;
1543 /* Fix namespace */
1544 copy->ns = NULL;
1545 }
1546 setNode(0, checkCopy((xmlNodePtr) copy));
1547 break;
1548 }
1549
1550 case OP_XML_COPY_PROP_LIST: {
1551 xmlAttrPtr copy;
1552
1553 startOp("xmlCopyPropList");
1554 copy = xmlCopyPropList(
1555 getNode(0),
1556 getAttr(1));
1557 if (copy != NULL)
1558 oomReport = 0;
1559 xmlFreePropList(copy);
1560 endOp();
1561 break;
1562 }
1563
1564 case OP_XML_COPY_DTD: {
1565 xmlDtdPtr dtd, copy;
1566
1567 startOp("xmlCopyDtd");
1568 incNodeIdx();
1569 copy = xmlCopyDtd(
1570 dtd = getDtd(1));
1571 oomReport = (dtd != NULL && copy == NULL);
1572 setNode(0, checkCopy((xmlNodePtr) copy));
1573 break;
1574 }
1575
1576 case OP_NODE_PARENT:
1577 case OP_NODE_NEXT_SIBLING:
1578 case OP_NODE_PREV_SIBLING:
1579 case OP_NODE_FIRST_CHILD:
1580 case OP_XML_GET_LAST_CHILD:
1581 case OP_XML_GET_INT_SUBSET:
1582 case OP_XML_DOC_GET_ROOT_ELEMENT:
1583 opNodeAccessor(op);
1584 oomReport = 0;
1585 break;
1586
1587 case OP_NODE_NAME: {
1588 xmlNodePtr node;
1589
1590 startOp("name");
1591 incStrIdx();
1592 node = getNode(0);
1593 copyStr(0, node ? node->name : NULL);
1594 oomReport = 0;
1595 endOp();
1596 break;
1597 }
1598
1599 case OP_XML_NODE_SET_NAME:
1600 startOp("xmlNodeSetName");
1601 xmlNodeSetName(
1602 getNode(0),
1603 getStr(0));
1604 endOp();
1605 break;
1606
1607 case OP_XML_NODE_GET_CONTENT: {
1608 xmlChar *content;
1609
1610 incStrIdx();
1611 startOp("xmlNodeGetContent");
1612 content = xmlNodeGetContent(getNode(0));
1613 if (content != NULL)
1614 oomReport = 0;
1615 moveStr(0, content);
1616 endOp();
1617 break;
1618 }
1619
1620 case OP_XML_NODE_SET_CONTENT: {
1621 xmlNodePtr node;
1622 int res;
1623
1624 startOp("xmlNodeSetContent");
1625 node = getNode(0);
1626 removeChildren(node, 0);
1627 res = xmlNodeSetContent(
1628 node,
1629 getStr(0));
1630 oomReport = (res < 0);
1631 endOp();
1632 break;
1633 }
1634
1635 case OP_XML_NODE_SET_CONTENT_LEN: {
1636 xmlNodePtr node;
1637 const xmlChar *content;
1638 int res;
1639
1640 startOp("xmlNodeSetContentLen");
1641 node = getNode(0);
1642 content = getStr(0);
1643 removeChildren(node, 0);
1644 res = xmlNodeSetContentLen(
1645 node,
1646 content,
1647 xmlStrlen(content));
1648 oomReport = (res < 0);
1649 endOp();
1650 break;
1651 }
1652
1653 case OP_XML_NODE_ADD_CONTENT: {
1654 xmlNodePtr node, text;
1655 int res;
1656
1657 startOp("xmlNodeAddContent");
1658 node = getNode(0);
1659 res = xmlNodeAddContent(
1660 node,
1661 getStr(0));
1662 oomReport = (res < 0);
1663 if (node != NULL) {
1664 if (node->type == XML_ELEMENT_NODE ||
1665 node->type == XML_DOCUMENT_FRAG_NODE)
1666 text = node->last;
1667 else
1668 text = node;
1669 checkContent(text);
1670 }
1671 endOp();
1672 break;
1673 }
1674
1675 case OP_XML_NODE_ADD_CONTENT_LEN: {
1676 xmlNodePtr node, text;
1677 const xmlChar *content;
1678 int res;
1679
1680 startOp("xmlNodeAddContentLen");
1681 node = getNode(0);
1682 content = getStr(0);
1683 res = xmlNodeAddContentLen(
1684 node,
1685 content,
1686 xmlStrlen(content));
1687 oomReport = res < 0;
1688 if (node != NULL) {
1689 if (node->type == XML_ELEMENT_NODE ||
1690 node->type == XML_DOCUMENT_FRAG_NODE)
1691 text = node->last;
1692 else
1693 text = node;
1694 checkContent(text);
1695 }
1696 endOp();
1697 break;
1698 }
1699
1700 case OP_XML_GET_LINE_NO:
1701 incIntIdx();
1702 startOp("xmlGetLineNo");
1703 setInt(0, xmlGetLineNo(getNode(0)));
1704 oomReport = 0;
1705 endOp();
1706 break;
1707
1708 case OP_XML_GET_NODE_PATH: {
1709 xmlChar *path;
1710
1711 incStrIdx();
1712 startOp("xmlGetNodePath");
1713 path = xmlGetNodePath(getNode(0));
1714 if (path != NULL)
1715 oomReport = 0;
1716 moveStr(0, path);
1717 endOp();
1718 break;
1719 }
1720
1721 case OP_XML_DOC_SET_ROOT_ELEMENT: {
1722 xmlDocPtr oldDoc, doc;
1723 xmlNodePtr oldRoot, oldParent, root;
1724
1725 startOp("xmlDocSetRootElement");
1726 incNodeIdx();
1727 doc = getDoc(1);
1728 root = getNode(2);
1729 if (doc != NULL && doc->parent != NULL)
1730 doc = NULL;
1731 if (!isValidChild((xmlNodePtr) doc, root))
1732 root = NULL;
1733 oldDoc = root ? root->doc : NULL;
1734 oldParent = root ? root->parent : NULL;
1735
1736 oldRoot = xmlDocSetRootElement(doc, root);
1737 /* We can't really know whether xmlSetTreeDoc failed */
1738 if (oldRoot != NULL ||
1739 root == NULL ||
1740 root->doc == oldDoc)
1741 oomReport = 0;
1742 setNode(0, oldRoot);
1743
1744 if (root &&
1745 (root->parent != oldParent ||
1746 root->doc != oldDoc)) {
1747 if (fixNs(root) < 0)
1748 oomReport = 1;
1749 if (oldParent != NULL)
1750 dropNode(oldParent);
1751 else
1752 dropNode((xmlNodePtr) oldDoc);
1753 }
1754 endOp();
1755 break;
1756 }
1757
1758 case OP_XML_NODE_IS_TEXT:
1759 incIntIdx();
1760 startOp("xmlNodeIsText");
1761 setInt(0, xmlNodeIsText(getNode(0)));
1762 oomReport = 0;
1763 endOp();
1764 break;
1765
1766 case OP_XML_NODE_GET_ATTR_VALUE: {
1767 xmlChar *value = NULL;
1768 int res;
1769
1770 incStrIdx();
1771 startOp("xmlNodeGetAttrValue");
1772 res = xmlNodeGetAttrValue(
1773 getNode(0),
1774 getStr(1),
1775 getStr(2),
1776 &value);
1777 oomReport = (res < 0);
1778 moveStr(0, value);
1779 endOp();
1780 break;
1781 }
1782
1783 case OP_XML_NODE_GET_LANG: {
1784 xmlChar *lang;
1785
1786 incStrIdx();
1787 startOp("xmlNodeGetLang");
1788 lang = xmlNodeGetLang(getNode(0));
1789 if (lang != NULL)
1790 oomReport = 0;
1791 moveStr(0, lang);
1792 endOp();
1793 break;
1794 }
1795
1796 case OP_XML_NODE_SET_LANG: {
1797 xmlNodePtr node;
1798 xmlAttrPtr attr;
1799 int res;
1800
1801 startOp("xmlNodeSetLang");
1802 node = getNode(0);
1803 attr = xmlHasNsProp(
1804 node,
1805 BAD_CAST "lang",
1806 XML_XML_NAMESPACE);
1807 xmlFuzzResetMallocFailed();
1808 removeChildren((xmlNodePtr) attr, 0);
1809 res = xmlNodeSetLang(
1810 node,
1811 getStr(0));
1812 oomReport = (res < 0);
1813 endOp();
1814 break;
1815 }
1816
1817 case OP_XML_NODE_GET_SPACE_PRESERVE: {
1818 int res;
1819
1820 incIntIdx();
1821 startOp("xmlNodeGetSpacePreserve");
1822 res = xmlNodeGetSpacePreserve(getNode(0));
1823 if (res >= 0)
1824 oomReport = 0;
1825 setInt(0, res);
1826 endOp();
1827 break;
1828 }
1829
1830 case OP_XML_NODE_SET_SPACE_PRESERVE: {
1831 xmlNodePtr node;
1832 xmlAttrPtr attr;
1833 int res;
1834
1835 startOp("xmlNodeSetSpacePreserve");
1836 node = getNode(0);
1837 attr = xmlHasNsProp(
1838 node,
1839 BAD_CAST "space",
1840 XML_XML_NAMESPACE);
1841 xmlFuzzResetMallocFailed();
1842 removeChildren((xmlNodePtr) attr, 0);
1843 res = xmlNodeSetSpacePreserve(
1844 node,
1845 getInt(0));
1846 oomReport = (res < 0);
1847 endOp();
1848 break;
1849 }
1850
1851 case OP_XML_NODE_GET_BASE: {
1852 xmlChar *base;
1853
1854 incStrIdx();
1855 startOp("xmlNodeGetBase");
1856 base = xmlNodeGetBase(
1857 getDoc(0),
1858 getNode(1));
1859 if (base != NULL)
1860 oomReport = 0;
1861 moveStr(0, base);
1862 endOp();
1863 break;
1864 }
1865
1866 case OP_XML_NODE_GET_BASE_SAFE: {
1867 xmlChar *base;
1868 int res;
1869
1870 startOp("xmlNodeGetBaseSafe");
1871 incStrIdx();
1872 res = xmlNodeGetBaseSafe(
1873 getDoc(0),
1874 getNode(1),
1875 &base);
1876 oomReport = (res < 0);
1877 moveStr(0, base);
1878 endOp();
1879 break;
1880 }
1881
1882 case OP_XML_NODE_SET_BASE: {
1883 xmlNodePtr node;
1884 xmlAttrPtr attr;
1885 int res;
1886
1887 startOp("xmlNodeSetBase");
1888 node = getNode(0);
1889 attr = xmlHasNsProp(
1890 node,
1891 BAD_CAST "base",
1892 XML_XML_NAMESPACE);
1893 xmlFuzzResetMallocFailed();
1894 removeChildren((xmlNodePtr) attr, 0);
1895 res = xmlNodeSetBase(
1896 node,
1897 getStr(0));
1898 if (res == 0)
1899 oomReport = 0;
1900 endOp();
1901 break;
1902 }
1903
1904 case OP_XML_IS_BLANK_NODE:
1905 startOp("xmlIsBlankNode");
1906 incNodeIdx();
1907 setInt(0, xmlIsBlankNode(getNode(0)));
1908 oomReport = 0;
1909 break;
1910
1911 case OP_XML_HAS_PROP: {
1912 xmlNodePtr node;
1913 xmlAttrPtr attr;
1914
1915 startOp("xmlHasProp");
1916 incNodeIdx();
1917 attr = xmlHasProp(
1918 node = getNode(1),
1919 getStr(0));
1920 if (node != NULL &&
1921 node->doc != NULL &&
1922 node->doc->intSubset != NULL) {
1923 /*
1924 * xmlHasProp tries to look up default attributes,
1925 * requiring a memory allocation which isn't
1926 * checked.
1927 */
1928 if (attr != NULL)
1929 oomReport = 0;
1930 } else {
1931 oomReport = 0;
1932 }
1933 setNode(0, (xmlNodePtr) attr);
1934 break;
1935 }
1936
1937 case OP_XML_HAS_NS_PROP: {
1938 xmlNodePtr node;
1939 xmlAttrPtr attr;
1940
1941 startOp("xmlHasNsProp");
1942 incNodeIdx();
1943 attr = xmlHasNsProp(
1944 node = getNode(1),
1945 getStr(0),
1946 getStr(1));
1947 if (node != NULL &&
1948 node->doc != NULL &&
1949 node->doc->intSubset != NULL) {
1950 if (attr != NULL)
1951 oomReport = 0;
1952 } else {
1953 oomReport = 0;
1954 }
1955 setNode(0, (xmlNodePtr) attr);
1956 break;
1957 }
1958
1959 case OP_XML_GET_PROP: {
1960 xmlChar *content;
1961
1962 startOp("xmlGetProp");
1963 incStrIdx();
1964 content = xmlGetProp(
1965 getNode(0),
1966 getStr(1));
1967 if (content != NULL)
1968 oomReport = 0;
1969 moveStr(0, content);
1970 endOp();
1971 break;
1972 }
1973
1974 case OP_XML_GET_NS_PROP: {
1975 xmlChar *content;
1976
1977 startOp("xmlGetNsProp");
1978 incStrIdx();
1979 content = xmlGetNsProp(
1980 getNode(0),
1981 getStr(1),
1982 getStr(2));
1983 if (content != NULL)
1984 oomReport = 0;
1985 moveStr(0, content);
1986 endOp();
1987 break;
1988 }
1989
1990 case OP_XML_GET_NO_NS_PROP: {
1991 xmlChar *content;
1992
1993 startOp("xmlGetNoNsProp");
1994 incStrIdx();
1995 content = xmlGetNoNsProp(
1996 getNode(0),
1997 getStr(1));
1998 if (content != NULL)
1999 oomReport = 0;
2000 moveStr(0, content);
2001 endOp();
2002 break;
2003 }
2004
2005 case OP_XML_SET_PROP: {
2006 xmlNodePtr node;
2007 xmlAttrPtr oldAttr, attr;
2008 xmlNsPtr ns = NULL;
2009 const xmlChar *name, *value, *localName;
2010 xmlChar *prefix;
2011 int prefixLen;
2012
2013 startOp("xmlSetProp");
2014 incNodeIdx();
2015 node = getNode(1);
2016 name = getStr(0);
2017 value = getStr(1);
2018
2019 /*
2020 * Find the old attribute node which will be deleted.
2021 */
2022 localName = xmlSplitQName3(name, &prefixLen);
2023 if (localName != NULL) {
2024 prefix = uncheckedStrndup(name, prefixLen);
2025 ns = xmlSearchNs(NULL, node, prefix);
2026 xmlFree(prefix);
2027 }
2028 if (ns == NULL)
2029 oldAttr = xmlHasNsProp(node, name, NULL);
2030 else
2031 oldAttr = xmlHasNsProp(node, localName, ns->href);
2032 xmlFuzzResetMallocFailed();
2033 if (oldAttr != NULL)
2034 removeChildren((xmlNodePtr) oldAttr, 0);
2035
2036 attr = xmlSetProp(node, name, value);
2037
2038 oomReport =
2039 (node != NULL && node->type == XML_ELEMENT_NODE &&
2040 name != NULL &&
2041 attr == NULL);
2042 setNode(0, (xmlNodePtr) attr);
2043 break;
2044 }
2045
2046 case OP_XML_SET_NS_PROP: {
2047 xmlNodePtr node;
2048 xmlNsPtr ns;
2049 xmlAttrPtr oldAttr, attr;
2050 const xmlChar *name, *value;
2051
2052 startOp("xmlSetNsProp");
2053 incNodeIdx();
2054 node = getNode(1);
2055 ns = nodeGetNs(getNode(2), getInt(0));
2056 name = getStr(0);
2057 value = getStr(1);
2058 oldAttr = xmlHasNsProp(node, name, ns ? ns->href : NULL);
2059 xmlFuzzResetMallocFailed();
2060 if (oldAttr != NULL)
2061 removeChildren((xmlNodePtr) oldAttr, 0);
2062 attr = xmlSetNsProp(node, ns, name, value);
2063 oomReport =
2064 ((node == NULL || node->type == XML_ELEMENT_NODE) &&
2065 (ns == NULL || ns->href != NULL) &&
2066 name != NULL &&
2067 attr == NULL);
2068 setNode(0, (xmlNodePtr) attr);
2069 if (ns != NULL) {
2070 if (fixNs((xmlNodePtr) attr) < 0)
2071 oomReport = 1;
2072 }
2073 break;
2074 }
2075
2076 case OP_XML_REMOVE_PROP: {
2077 xmlNodePtr attr, parent = NULL;
2078
2079 startOp("xmlRemoveProp");
2080 incIntIdx();
2081 attr = getNode(0);
2082 if (attr != NULL) {
2083 if (attr->parent != NULL &&
2084 attr->type == XML_ATTRIBUTE_NODE)
2085 removeChildren(attr, 1);
2086 else
2087 attr = NULL;
2088 }
2089 if (attr != NULL)
2090 parent = attr->parent;
2091 setInt(0, xmlRemoveProp((xmlAttrPtr) attr));
2092 oomReport = 0;
2093 dropNode(parent);
2094 endOp();
2095 break;
2096 }
2097
2098 case OP_XML_UNSET_PROP: {
2099 xmlNodePtr node;
2100 xmlAttrPtr attr;
2101 const xmlChar *name;
2102
2103 startOp("xmlUnsetProp");
2104 incIntIdx();
2105 node = getNode(0);
2106 name = getStr(0);
2107 attr = xmlHasNsProp(node, name, NULL);
2108 xmlFuzzResetMallocFailed();
2109 if (attr != NULL)
2110 removeChildren((xmlNodePtr) attr, 1);
2111 setInt(0, xmlUnsetProp(node, name));
2112 oomReport = 0;
2113 dropNode(node);
2114 endOp();
2115 break;
2116 }
2117
2118 case OP_XML_UNSET_NS_PROP: {
2119 xmlNodePtr node;
2120 xmlNsPtr ns;
2121 xmlAttrPtr attr;
2122 const xmlChar *name;
2123
2124 startOp("xmlUnsetNsProp");
2125 incIntIdx();
2126 node = getNode(0);
2127 ns = nodeGetNs(getNode(1), getInt(1));
2128 name = getStr(0);
2129 attr = xmlHasNsProp(node, name, ns ? ns->href : NULL);
2130 xmlFuzzResetMallocFailed();
2131 if (attr != NULL)
2132 removeChildren((xmlNodePtr) attr, 1);
2133 setInt(0, xmlUnsetNsProp(node, ns, name));
2134 oomReport = 0;
2135 dropNode(node);
2136 endOp();
2137 break;
2138 }
2139
2140 case OP_XML_NEW_NS: {
2141 xmlNodePtr node;
2142 xmlNsPtr ns;
2143
2144 startOp("xmlNewNs");
2145 ns = xmlNewNs(
2146 node = getNode(0),
2147 getStr(0),
2148 getStr(1));
2149 if (ns != NULL)
2150 oomReport = 0;
2151 if (node == NULL)
2152 xmlFreeNs(ns);
2153 endOp();
2154 break;
2155 }
2156
2157 case OP_XML_SEARCH_NS: {
2158 xmlNsPtr ns;
2159
2160 startOp("xmlSearchNs");
2161 ns = xmlSearchNs(
2162 getDoc(0),
2163 getNode(1),
2164 getStr(0));
2165 if (ns != NULL)
2166 oomReport = 0;
2167 endOp();
2168 break;
2169 }
2170
2171 case OP_XML_SEARCH_NS_BY_HREF: {
2172 xmlNsPtr ns;
2173
2174 startOp("xmlSearchNsByHref");
2175 ns = xmlSearchNsByHref(
2176 getDoc(0),
2177 getNode(1),
2178 getStr(0));
2179 if (ns != NULL)
2180 oomReport = 0;
2181 endOp();
2182 break;
2183 }
2184
2185 case OP_XML_GET_NS_LIST: {
2186 xmlNsPtr *list;
2187
2188 startOp("xmlGetNsList");
2189 list = xmlGetNsList(
2190 getDoc(0),
2191 getNode(1));
2192 if (list != NULL)
2193 oomReport = 0;
2194 xmlFree(list);
2195 endOp();
2196 break;
2197 }
2198
2199 case OP_XML_GET_NS_LIST_SAFE: {
2200 xmlNsPtr *list;
2201 int res;
2202
2203 startOp("xmlGetNsList");
2204 res = xmlGetNsListSafe(
2205 getDoc(0),
2206 getNode(1),
2207 &list);
2208 oomReport = (res < 0);
2209 xmlFree(list);
2210 endOp();
2211 break;
2212 }
2213
2214 case OP_XML_SET_NS: {
2215 xmlNodePtr node;
2216 xmlNsPtr ns;
2217
2218 startOp("xmlSetNs");
2219 node = getNode(0),
2220 ns = nodeGetNs(getNode(1), getInt(0));
2221 xmlSetNs(node, ns);
2222 oomReport = 0;
2223 if (ns != NULL) {
2224 if (fixNs(node) < 0)
2225 oomReport = 1;
2226 }
2227 endOp();
2228 break;
2229 }
2230
2231 case OP_XML_COPY_NAMESPACE: {
2232 xmlNsPtr ns, copy;
2233
2234 startOp("xmlCopyNamespace");
2235 copy = xmlCopyNamespace(
2236 ns = nodeGetNs(getNode(0), getInt(0)));
2237 oomReport = (ns != NULL && copy == NULL);
2238 xmlFreeNs(copy);
2239 endOp();
2240 break;
2241 }
2242
2243 case OP_XML_COPY_NAMESPACE_LIST: {
2244 xmlNsPtr list, copy;
2245
2246 startOp("xmlCopyNamespaceList");
2247 copy = xmlCopyNamespaceList(
2248 list = nodeGetNs(getNode(0), getInt(0)));
2249 oomReport = (list != NULL && copy == NULL);
2250 xmlFreeNsList(copy);
2251 endOp();
2252 break;
2253 }
2254
2255 case OP_XML_UNLINK_NODE: {
2256 xmlNodePtr node, oldParent;
2257 xmlDocPtr doc;
2258
2259 startOp("xmlUnlinkNode");
2260 node = getNode(0);
2261 doc = node ? node->doc : NULL;
2262 /*
2263 * Unlinking DTD children can cause invalid references
2264 * which would be expensive to fix.
2265 *
2266 * Don't unlink DTD if it is the internal or external
2267 * subset of the document.
2268 */
2269 if (node != NULL &&
2270 (isDtdChild(node) ||
2271 (node->type == XML_DTD_NODE &&
2272 doc != NULL &&
2273 ((xmlDtdPtr) node == doc->intSubset ||
2274 (xmlDtdPtr) node == doc->extSubset))))
2275 node = NULL;
2276 oldParent = node ? node->parent : NULL;
2277 xmlUnlinkNode(node);
2278 oomReport = 0;
2279 if (node != NULL && node->parent != oldParent) {
2280 if (fixNs(node) < 0)
2281 oomReport = 1;
2282 dropNode(oldParent);
2283 }
2284 endOp();
2285 break;
2286 }
2287
2288 case OP_XML_REPLACE_NODE: {
2289 xmlNodePtr old, oldParent, node, oldNodeParent, result;
2290 xmlDocPtr oldNodeDoc;
2291
2292 startOp("xmlReplaceNode");
2293 old = getNode(0);
2294 node = getNode(1);
2295
2296 /*
2297 * Unlinking DTD children can cause invalid references
2298 * which would be expensive to fix.
2299 */
2300 if (isDtdChild(old))
2301 old = NULL;
2302 if (old != NULL && !isValidChild(old->parent, node))
2303 node = NULL;
2304
2305 oldParent = old ? old->parent : NULL;
2306 oldNodeParent = node ? node->parent : NULL;
2307 oldNodeDoc = node ? node->doc : NULL;
2308
2309 result = xmlReplaceNode(old, node);
2310 oomReport =
2311 (old != NULL && old->parent != NULL &&
2312 node != NULL &&
2313 old != node &&
2314 result == NULL);
2315
2316 if (old != NULL && old->parent != oldParent) {
2317 if (fixNs(old) < 0)
2318 oomReport = 1;
2319 }
2320 if (node == NULL) {
2321 /* Old node was unlinked */
2322 dropNode(oldParent);
2323 } else if (node->parent != oldNodeParent ||
2324 node->doc != oldNodeDoc) {
2325 if (fixNs(node) < 0)
2326 oomReport = 1;
2327 /* Drop old parent of new node */
2328 if (oldNodeParent != NULL)
2329 dropNode(oldNodeParent);
2330 else
2331 dropNode((xmlNodePtr) oldNodeDoc);
2332 }
2333 endOp();
2334 break;
2335 }
2336
2337 case OP_XML_ADD_CHILD:
2338 case OP_XML_ADD_SIBLING:
2339 case OP_XML_ADD_PREV_SIBLING:
2340 case OP_XML_ADD_NEXT_SIBLING: {
2341 xmlNodePtr target, parent, node, oldNodeParent, result;
2342 xmlDocPtr oldNodeDoc;
2343 int argsOk;
2344
2345 switch (op) {
2346 case OP_XML_ADD_CHILD:
2347 startOp("xmlAddChild"); break;
2348 case OP_XML_ADD_SIBLING:
2349 startOp("xmlAddSibling"); break;
2350 case OP_XML_ADD_PREV_SIBLING:
2351 startOp("xmlAddPrevSibling"); break;
2352 case OP_XML_ADD_NEXT_SIBLING:
2353 startOp("xmlAddNextSibling"); break;
2354 }
2355
2356 if (op == OP_XML_ADD_CHILD) {
2357 target = NULL;
2358 parent = getNode(0);
2359 } else {
2360 target = getNode(0);
2361 parent = target ? target->parent : NULL;
2362 }
2363 node = getNode(1);
2364
2365 /* Don't append to root node */
2366 if (target != NULL && parent == NULL)
2367 node = NULL;
2368
2369 /* Check tree structure */
2370 if (isDtdChild(node) ||
2371 !isValidChild(parent, node))
2372 node = NULL;
2373
2374 /* Attributes */
2375 if (node != NULL && node->type == XML_ATTRIBUTE_NODE) {
2376 if ((op == OP_XML_ADD_CHILD) ||
2377 ((target != NULL &&
2378 (target->type == XML_ATTRIBUTE_NODE)))) {
2379 xmlAttrPtr attr = xmlHasNsProp(parent, node->name,
2380 node->ns ? node->ns->href : NULL);
2381
2382 xmlFuzzResetMallocFailed();
2383 /* Attribute might be replaced */
2384 if (attr != NULL && attr != (xmlAttrPtr) node)
2385 removeChildren((xmlNodePtr) attr, 1);
2386 } else {
2387 target = NULL;
2388 }
2389 } else if (target != NULL &&
2390 target->type == XML_ATTRIBUTE_NODE) {
2391 node = NULL;
2392 }
2393
2394 oldNodeParent = node ? node->parent : NULL;
2395 oldNodeDoc = node ? node->doc : NULL;
2396 argsOk =
2397 (target != NULL &&
2398 node != NULL &&
2399 target != node);
2400
2401 switch (op) {
2402 case OP_XML_ADD_CHILD:
2403 argsOk = (parent != NULL && node != NULL);
2404 result = xmlAddChild(parent, node);
2405 break;
2406 case OP_XML_ADD_SIBLING:
2407 result = xmlAddSibling(target, node);
2408 break;
2409 case OP_XML_ADD_PREV_SIBLING:
2410 result = xmlAddPrevSibling(target, node);
2411 break;
2412 case OP_XML_ADD_NEXT_SIBLING:
2413 result = xmlAddNextSibling(target, node);
2414 break;
2415 }
2416 oomReport = (argsOk && result == NULL);
2417
2418 if (result != NULL && result != node) {
2419 /* Text node was merged */
2420 removeNode(node);
2421 checkContent(result);
2422 /* Drop old parent of node */
2423 if (oldNodeParent != NULL)
2424 dropNode(oldNodeParent);
2425 else
2426 dropNode((xmlNodePtr) oldNodeDoc);
2427 } else if (node != NULL &&
2428 (node->parent != oldNodeParent ||
2429 node->doc != oldNodeDoc)) {
2430 if (fixNs(node) < 0)
2431 oomReport = 1;
2432 /* Drop old parent of node */
2433 if (oldNodeParent != NULL)
2434 dropNode(oldNodeParent);
2435 else
2436 dropNode((xmlNodePtr) oldNodeDoc);
2437 }
2438
2439 endOp();
2440 break;
2441 }
2442
2443 case OP_XML_TEXT_MERGE: {
2444 xmlNodePtr first, second, parent = NULL, res;
2445 int argsOk;
2446
2447 startOp("xmlTextMerge");
2448 first = getNode(0);
2449 second = getNode(1);
2450 argsOk =
2451 (first != NULL && first->type == XML_TEXT_NODE &&
2452 second != NULL && second->type == XML_TEXT_NODE &&
2453 first != second &&
2454 first->name == second->name);
2455 if (argsOk) {
2456 if (second->parent != NULL)
2457 parent = second->parent;
2458 else
2459 parent = (xmlNodePtr) second->doc;
2460
2461 }
2462 res = xmlTextMerge(first, second);
2463 oomReport = (argsOk && res == NULL);
2464 if (res != NULL) {
2465 removeNode(second);
2466 dropNode(parent);
2467 checkContent(first);
2468 }
2469 endOp();
2470 break;
2471 }
2472
2473 case OP_XML_TEXT_CONCAT: {
2474 xmlNodePtr node;
2475 const xmlChar *text;
2476 int res;
2477
2478 startOp("xmlTextConcat");
2479 node = getNode(0);
2480 text = getStr(0);
2481 res = xmlTextConcat(
2482 node,
2483 text,
2484 xmlStrlen(text));
2485 oomReport = (isTextContentNode(node) && res < 0);
2486 checkContent(node);
2487 endOp();
2488 break;
2489 }
2490
2491 case OP_XML_STRING_GET_NODE_LIST: {
2492 xmlNodePtr list;
2493 const xmlChar *value;
2494
2495 startOp("xmlStringGetNodeList");
2496 list = xmlStringGetNodeList(
2497 getDoc(0),
2498 value = getStr(0));
2499 oomReport = (value != NULL && list == NULL);
2500 xmlFreeNodeList(list);
2501 endOp();
2502 break;
2503 }
2504
2505 case OP_XML_STRING_LEN_GET_NODE_LIST: {
2506 xmlDocPtr doc;
2507 xmlNodePtr list;
2508 const xmlChar *value;
2509
2510 startOp("xmlStringLenGetNodeList");
2511 doc = getDoc(0);
2512 value = getStr(0);
2513 list = xmlStringLenGetNodeList(
2514 doc,
2515 value,
2516 xmlStrlen(value));
2517 oomReport = (value != NULL && list == NULL);
2518 xmlFreeNodeList(list);
2519 endOp();
2520 break;
2521 }
2522
2523 case OP_XML_NODE_LIST_GET_STRING: {
2524 xmlChar *string;
2525
2526 startOp("xmlNodeListGetString");
2527 incStrIdx();
2528 string = xmlNodeListGetString(
2529 getDoc(0),
2530 getNode(1),
2531 getInt(0));
2532 oomReport = (string == NULL);
2533 moveStr(0, string);
2534 endOp();
2535 break;
2536 }
2537
2538 case OP_XML_NODE_LIST_GET_RAW_STRING: {
2539 xmlChar *string;
2540
2541 startOp("xmlNodeListGetRawString");
2542 incStrIdx();
2543 string = xmlNodeListGetRawString(
2544 getDoc(0),
2545 getNode(1),
2546 getInt(0));
2547 oomReport = (string == NULL);
2548 moveStr(0, string);
2549 endOp();
2550 break;
2551 }
2552
2553 case OP_XML_IS_XHTML:
2554 startOp("xmlIsXHTML");
2555 incIntIdx();
2556 setInt(0, xmlIsXHTML(
2557 getStr(0),
2558 getStr(1)));
2559 oomReport = 0;
2560 break;
2561
2562 case OP_XML_ADD_ELEMENT_DECL: {
2563 xmlElementPtr decl;
2564
2565 startOp("xmlAddElementDecl");
2566 incNodeIdx();
2567 decl = xmlAddElementDecl(
2568 NULL,
2569 getDtd(1),
2570 getStr(0),
2571 (xmlElementTypeVal) getInt(0),
2572 NULL);
2573 if (decl != NULL)
2574 oomReport = 0;
2575 setNode(0, (xmlNodePtr) decl);
2576 break;
2577 }
2578
2579 case OP_XML_ADD_ATTRIBUTE_DECL: {
2580 xmlAttributePtr decl;
2581
2582 startOp("xmlAddAttributeDecl");
2583 incNodeIdx();
2584 decl = xmlAddAttributeDecl(
2585 NULL,
2586 getDtd(1),
2587 getStr(0),
2588 getStr(1),
2589 getStr(2),
2590 (xmlAttributeType) getInt(0),
2591 (xmlAttributeDefault) getInt(1),
2592 getStr(3),
2593 NULL);
2594 if (decl != NULL)
2595 oomReport = 0;
2596 setNode(0, (xmlNodePtr) decl);
2597 break;
2598 }
2599
2600 case OP_XML_ADD_NOTATION_DECL: {
2601 xmlNotationPtr decl;
2602
2603 startOp("xmlAddNotationDecl");
2604 decl = xmlAddNotationDecl(
2605 NULL,
2606 getDtd(1),
2607 getStr(0),
2608 getStr(1),
2609 getStr(2));
2610 if (decl != NULL)
2611 oomReport = 0;
2612 endOp();
2613 break;
2614 }
2615
2616 case OP_XML_GET_DTD_ELEMENT_DESC: {
2617 xmlElementPtr elem;
2618
2619 startOp("xmlGetDtdElementDesc");
2620 incNodeIdx();
2621 elem = xmlGetDtdElementDesc(
2622 getDtd(1),
2623 getStr(0));
2624 if (elem != NULL)
2625 oomReport = 0;
2626 /*
2627 * Don't reference XML_ELEMENT_TYPE_UNDEFINED dummy
2628 * declarations.
2629 */
2630 if (elem != NULL && elem->parent == NULL)
2631 elem = NULL;
2632 setNode(0, (xmlNodePtr) elem);
2633 break;
2634 }
2635
2636 case OP_XML_GET_DTD_QELEMENT_DESC: {
2637 xmlElementPtr elem;
2638
2639 startOp("xmlGetDtdQElementDesc");
2640 incNodeIdx();
2641 elem = xmlGetDtdQElementDesc(
2642 getDtd(1),
2643 getStr(0),
2644 getStr(1));
2645 oomReport = 0;
2646 if (elem != NULL && elem->parent == NULL)
2647 elem = NULL;
2648 setNode(0, (xmlNodePtr) elem);
2649 break;
2650 }
2651
2652 case OP_XML_GET_DTD_ATTR_DESC: {
2653 xmlAttributePtr decl;
2654
2655 startOp("xmlGetDtdAttrDesc");
2656 incNodeIdx();
2657 decl = xmlGetDtdAttrDesc(
2658 getDtd(1),
2659 getStr(0),
2660 getStr(1));
2661 if (decl != NULL)
2662 oomReport = 0;
2663 setNode(0, (xmlNodePtr) decl);
2664 break;
2665 }
2666
2667 case OP_XML_GET_DTD_QATTR_DESC: {
2668 xmlAttributePtr decl;
2669
2670 startOp("xmlGetDtdQAttrDesc");
2671 incNodeIdx();
2672 decl = xmlGetDtdQAttrDesc(
2673 getDtd(1),
2674 getStr(0),
2675 getStr(1),
2676 getStr(2));
2677 oomReport = 0;
2678 setNode(0, (xmlNodePtr) decl);
2679 break;
2680 }
2681
2682 case OP_XML_GET_DTD_NOTATION_DESC:
2683 startOp("xmlGetDtdNotationDesc");
2684 xmlGetDtdNotationDesc(
2685 getDtd(1),
2686 getStr(0));
2687 oomReport = 0;
2688 endOp();
2689 break;
2690
2691 case OP_XML_ADD_ID:
2692 startOp("xmlAddID");
2693 xmlAddID(
2694 NULL,
2695 getDoc(0),
2696 getStr(0),
2697 getAttr(1));
2698 endOp();
2699 break;
2700
2701 case OP_XML_ADD_ID_SAFE: {
2702 int res;
2703
2704 startOp("xmlAddIDSafe");
2705 res = xmlAddIDSafe(
2706 getAttr(0),
2707 getStr(0));
2708 oomReport = (res < 0);
2709 endOp();
2710 break;
2711 }
2712
2713 case OP_XML_GET_ID:
2714 startOp("xmlGetID");
2715 incNodeIdx();
2716 setNode(0, (xmlNodePtr) xmlGetID(
2717 getDoc(1),
2718 getStr(0)));
2719 oomReport = 0;
2720 break;
2721
2722 case OP_XML_IS_ID: {
2723 int res;
2724
2725 startOp("xmlIsID");
2726 res = xmlIsID(
2727 getDoc(2),
2728 getNode(1),
2729 getAttr(0));
2730 oomReport = (res < 0);
2731 endOp();
2732 break;
2733 }
2734
2735 case OP_XML_REMOVE_ID:
2736 startOp("xmlRemoveID");
2737 xmlRemoveID(
2738 getDoc(1),
2739 getAttr(0));
2740 oomReport = 0;
2741 endOp();
2742 break;
2743
2744 case OP_XML_ADD_REF: {
2745 xmlDocPtr doc;
2746 xmlAttrPtr attr;
2747 xmlRefPtr ref;
2748 const xmlChar *value;
2749
2750 startOp("xmlAddRef");
2751 ref = xmlAddRef(
2752 NULL,
2753 doc = getDoc(0),
2754 value = getStr(0),
2755 attr = getAttr(1));
2756 oomReport =
2757 (doc != NULL &&
2758 value != NULL &&
2759 attr != NULL &&
2760 ref == NULL);
2761 endOp();
2762 break;
2763 }
2764
2765 case OP_XML_GET_REFS:
2766 startOp("xmlGetRefs");
2767 xmlGetRefs(
2768 getDoc(1),
2769 getStr(0));
2770 oomReport = 0;
2771 endOp();
2772 break;
2773
2774 case OP_XML_IS_REF:
2775 startOp("xmlIsRef");
2776 xmlIsRef(
2777 getDoc(2),
2778 getNode(1),
2779 getAttr(0));
2780 oomReport = 0;
2781 endOp();
2782 break;
2783
2784 case OP_XML_REMOVE_REF: {
2785 int res;
2786
2787 startOp("xmlRemoveRef");
2788 res = xmlRemoveRef(
2789 getDoc(1),
2790 getAttr(0));
2791 if (res == 0)
2792 oomReport = 0;
2793 endOp();
2794 break;
2795 }
2796
2797 case OP_XML_NEW_ENTITY: {
2798 xmlDocPtr doc;
2799 xmlEntityPtr ent;
2800
2801 startOp("xmlNewEntity");
2802 incNodeIdx();
2803 ent = xmlNewEntity(
2804 doc = getDoc(1),
2805 getStr(0),
2806 getInt(0),
2807 getStr(1),
2808 getStr(2),
2809 getStr(3));
2810 if (ent != NULL)
2811 oomReport = 0;
2812 if (doc == NULL || doc->intSubset == NULL) {
2813 xmlFreeEntity(ent);
2814 ent = NULL;
2815 }
2816 setNode(0, (xmlNodePtr) ent);
2817 break;
2818 }
2819
2820 case OP_XML_ADD_ENTITY: {
2821 xmlEntityPtr ent;
2822 int res;
2823
2824 startOp("xmlAddEntity");
2825 incNodeIdx();
2826 res = xmlAddEntity(
2827 getDoc(1),
2828 getInt(0),
2829 getStr(0),
2830 getInt(1),
2831 getStr(1),
2832 getStr(2),
2833 getStr(3),
2834 &ent);
2835 oomReport = (res == XML_ERR_NO_MEMORY);
2836 setNode(0, (xmlNodePtr) ent);
2837 break;
2838 }
2839
2840 case OP_XML_ADD_DOC_ENTITY: {
2841 xmlEntityPtr ent;
2842
2843 startOp("xmlAddDocEntity");
2844 incNodeIdx();
2845 ent = xmlAddDocEntity(
2846 getDoc(1),
2847 getStr(0),
2848 getInt(1),
2849 getStr(1),
2850 getStr(2),
2851 getStr(3));
2852 if (ent != NULL)
2853 oomReport = 0;
2854 setNode(0, (xmlNodePtr) ent);
2855 break;
2856 }
2857
2858 case OP_XML_ADD_DTD_ENTITY: {
2859 xmlEntityPtr ent;
2860
2861 startOp("xmlAddDtdEntity");
2862 incNodeIdx();
2863 ent = xmlAddDtdEntity(
2864 getDoc(1),
2865 getStr(0),
2866 getInt(1),
2867 getStr(1),
2868 getStr(2),
2869 getStr(3));
2870 setNode(0, (xmlNodePtr) ent);
2871 break;
2872 }
2873
2874 case OP_XML_GET_PREDEFINED_ENTITY:
2875 startOp("xmlGetPredefinedEntity");
2876 incNodeIdx();
2877 setNode(0, (xmlNodePtr) xmlGetPredefinedEntity(
2878 getStr(0)));
2879 oomReport = 0;
2880 break;
2881
2882 case OP_XML_GET_DOC_ENTITY:
2883 startOp("xmlGetDocEntity");
2884 incNodeIdx();
2885 setNode(0, (xmlNodePtr) xmlGetDocEntity(
2886 getDoc(1),
2887 getStr(0)));
2888 oomReport = 0;
2889 break;
2890
2891 case OP_XML_GET_DTD_ENTITY:
2892 startOp("xmlGetDtdEntity");
2893 incNodeIdx();
2894 setNode(0, (xmlNodePtr) xmlGetDtdEntity(
2895 getDoc(1),
2896 getStr(0)));
2897 oomReport = 0;
2898 break;
2899
2900 case OP_XML_GET_PARAMETER_ENTITY:
2901 startOp("xmlGetParameterEntity");
2902 incNodeIdx();
2903 setNode(0, (xmlNodePtr) xmlGetParameterEntity(
2904 getDoc(1),
2905 getStr(0)));
2906 oomReport = 0;
2907 break;
2908
2909 case OP_XML_ENCODE_ENTITIES_REENTRANT: {
2910 const xmlChar *string;
2911 xmlChar *encoded;
2912
2913 startOp("xmlEncodeEntitiesReentrant");
2914 incStrIdx();
2915 encoded = xmlEncodeEntitiesReentrant(
2916 getDoc(0),
2917 string = getStr(1));
2918 oomReport = (string != NULL && encoded == NULL);
2919 moveStr(0, encoded);
2920 endOp();
2921 break;
2922 }
2923
2924 case OP_XML_ENCODE_SPECIAL_CHARS: {
2925 const xmlChar *string;
2926 xmlChar *encoded;
2927
2928 startOp("xmlEncodespecialChars");
2929 incStrIdx();
2930 encoded = xmlEncodeSpecialChars(
2931 getDoc(0),
2932 string = getStr(1));
2933 oomReport = (string != NULL && encoded == NULL);
2934 moveStr(0, encoded);
2935 endOp();
2936 break;
2937 }
2938
2939 #ifdef LIBXML_HTML_ENABLED
2940 case OP_HTML_NEW_DOC: {
2941 htmlDocPtr doc;
2942
2943 startOp("htmlNewDoc");
2944 incNodeIdx();
2945 doc = htmlNewDoc(
2946 getStr(0),
2947 getStr(1));
2948 oomReport = (doc == NULL);
2949 setNode(0, (xmlNodePtr) doc);
2950 break;
2951 }
2952
2953 case OP_HTML_NEW_DOC_NO_DTD: {
2954 htmlDocPtr doc;
2955
2956 startOp("htmlNewDocNoDtD");
2957 incNodeIdx();
2958 doc = htmlNewDocNoDtD(
2959 getStr(0),
2960 getStr(1));
2961 oomReport = (doc == NULL);
2962 setNode(0, (xmlNodePtr) doc);
2963 break;
2964 }
2965
2966 case OP_HTML_GET_META_ENCODING: {
2967 const xmlChar *encoding;
2968
2969 startOp("htmlGetMetaEncoding");
2970 incStrIdx();
2971 encoding = htmlGetMetaEncoding(getDoc(0));
2972 if (encoding != NULL)
2973 oomReport = 0;
2974 copyStr(0, encoding);
2975 break;
2976 }
2977
2978 case OP_HTML_SET_META_ENCODING:
2979 /* TODO (can destroy inner text) */
2980 break;
2981
2982 case OP_HTML_IS_BOOLEAN_ATTR:
2983 startOp("htmlIsBooleanAttr");
2984 htmlIsBooleanAttr(getStr(0));
2985 oomReport = 0;
2986 endOp();
2987 break;
2988 #endif
2989
2990 #ifdef LIBXML_VALID_ENABLED
2991 case OP_VALIDATE: {
2992 xmlNodePtr node;
2993 int type;
2994 int res = 1;
2995
2996 startOp("validate");
2997 incIntIdx();
2998 node = getNode(0);
2999 type = node ? node->type : 0;
3000 xmlValidCtxtPtr vctxt = xmlNewValidCtxt();
3001 xmlFuzzResetMallocFailed();
3002
3003 switch (type) {
3004 case XML_DOCUMENT_NODE:
3005 case XML_HTML_DOCUMENT_NODE:
3006 res = xmlValidateDocument(vctxt, (xmlDocPtr) node);
3007 break;
3008 case XML_ELEMENT_DECL:
3009 res = xmlValidateElementDecl(vctxt, node->doc,
3010 (xmlElementPtr) node);
3011 break;
3012 case XML_ATTRIBUTE_DECL:
3013 res = xmlValidateAttributeDecl(vctxt, node->doc,
3014 (xmlAttributePtr) node);
3015 break;
3016 case XML_ELEMENT_NODE:
3017 res = xmlValidateElement(vctxt, node->doc, node);
3018 break;
3019 default:
3020 break;
3021 }
3022
3023 if (res != 0)
3024 oomReport = 0;
3025 xmlFreeValidCtxt(vctxt);
3026 setInt(0, res);
3027 endOp();
3028 break;
3029 }
3030
3031 case OP_XML_VALIDATE_DTD: {
3032 xmlValidCtxtPtr vctxt;
3033 int res;
3034
3035 startOp("xmlValidateDtd");
3036 incIntIdx();
3037 vctxt = xmlNewValidCtxt();
3038 res = xmlValidateDtd(
3039 vctxt,
3040 getDoc(0),
3041 getDtd(1));
3042 if (res != 0)
3043 oomReport = 0;
3044 xmlFreeValidCtxt(vctxt);
3045 setInt(0, res);
3046 endOp();
3047 break;
3048 }
3049 #endif /* LIBXML_VALID_ENABLED */
3050
3051 #ifdef LIBXML_OUTPUT_ENABLED
3052 case OP_XML_DOC_DUMP_MEMORY:
3053 case OP_XML_DOC_DUMP_MEMORY_ENC:
3054 case OP_XML_DOC_DUMP_FORMAT_MEMORY:
3055 case OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC:
3056 case OP_HTML_DOC_DUMP_MEMORY:
3057 case OP_HTML_DOC_DUMP_MEMORY_FORMAT: {
3058 xmlDocPtr doc;
3059 xmlChar *out = NULL;
3060 int outSize = 0;
3061
3062 switch (op) {
3063 case OP_XML_DOC_DUMP_MEMORY:
3064 startOp("xmlDocDumpMemory"); break;
3065 case OP_XML_DOC_DUMP_MEMORY_ENC:
3066 startOp("xmlDocDumpMemoryEnc"); break;
3067 case OP_XML_DOC_DUMP_FORMAT_MEMORY:
3068 startOp("xmlDocDumpFormatMemory"); break;
3069 case OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC:
3070 startOp("xmlDocDumpFormatMemoryEnc"); break;
3071 case OP_HTML_DOC_DUMP_MEMORY:
3072 startOp("htmlDocDumpMemory"); break;
3073 case OP_HTML_DOC_DUMP_MEMORY_FORMAT:
3074 startOp("htmlDocDumpMemoryFormat"); break;
3075 }
3076
3077 incStrIdx();
3078 doc = getDoc(0);
3079
3080 switch (op) {
3081 case OP_XML_DOC_DUMP_MEMORY:
3082 xmlDocDumpMemory(doc, &out, &outSize);
3083 break;
3084 case OP_XML_DOC_DUMP_MEMORY_ENC:
3085 xmlDocDumpMemoryEnc(doc, &out, &outSize,
3086 (const char *) getStr(1));
3087 break;
3088 case OP_XML_DOC_DUMP_FORMAT_MEMORY:
3089 xmlDocDumpFormatMemory(doc, &out, &outSize,
3090 getInt(0));
3091 break;
3092 case OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC:
3093 xmlDocDumpFormatMemoryEnc(doc, &out, &outSize,
3094 (const char *) getStr(1),
3095 getInt(0));
3096 break;
3097 #ifdef LIBXML_HTML_ENABLED
3098 case OP_HTML_DOC_DUMP_MEMORY:
3099 htmlDocDumpMemory(doc, &out, &outSize);
3100 break;
3101 case OP_HTML_DOC_DUMP_MEMORY_FORMAT:
3102 htmlDocDumpMemoryFormat(doc, &out, &outSize,
3103 getInt(0));
3104 break;
3105 #endif /* LIBXML_HTML_ENABLED */
3106 }
3107
3108 /* Could be an unknown encoding */
3109 if (out != NULL)
3110 oomReport = 0;
3111 moveStr(0, out);
3112 endOp();
3113 break;
3114 }
3115
3116 case OP_XML_NODE_DUMP:
3117 case OP_XML_NODE_BUF_GET_CONTENT:
3118 case OP_XML_ATTR_SERIALIZE_TXT_CONTENT:
3119 case OP_XML_DUMP_ELEMENT_DECL:
3120 case OP_XML_DUMP_ELEMENT_TABLE:
3121 case OP_XML_DUMP_ATTRIBUTE_DECL:
3122 case OP_XML_DUMP_ATTRIBUTE_TABLE:
3123 case OP_XML_DUMP_ENTITY_DECL:
3124 case OP_XML_DUMP_ENTITIES_TABLE:
3125 case OP_XML_DUMP_NOTATION_DECL:
3126 case OP_XML_DUMP_NOTATION_TABLE:
3127 case OP_HTML_NODE_DUMP: {
3128 xmlNodePtr node;
3129 xmlDocPtr doc;
3130 xmlBufferPtr buffer;
3131 xmlChar *dump;
3132 int level, format, res;
3133
3134 switch (op) {
3135 case OP_XML_NODE_DUMP:
3136 startOp("xmlNodeDump"); break;
3137 case OP_XML_NODE_BUF_GET_CONTENT:
3138 startOp("xmlNodeBufGetContent"); break;
3139 case OP_XML_ATTR_SERIALIZE_TXT_CONTENT:
3140 startOp("xmlAttrSerializeTxtContent"); break;
3141 case OP_XML_DUMP_ELEMENT_DECL:
3142 startOp("xmlDumpElementDecl"); break;
3143 case OP_XML_DUMP_ELEMENT_TABLE:
3144 startOp("xmlDumpElementTable"); break;
3145 case OP_XML_DUMP_ATTRIBUTE_DECL:
3146 startOp("xmlDumpAttributeDecl"); break;
3147 case OP_XML_DUMP_ATTRIBUTE_TABLE:
3148 startOp("xmlDumpAttributeTable"); break;
3149 case OP_XML_DUMP_ENTITY_DECL:
3150 startOp("xmlDumpEntityDecl"); break;
3151 case OP_XML_DUMP_ENTITIES_TABLE:
3152 startOp("xmlDumpEntitiesTable"); break;
3153 case OP_XML_DUMP_NOTATION_DECL:
3154 startOp("xmlDumpNotationDecl"); break;
3155 case OP_XML_DUMP_NOTATION_TABLE:
3156 startOp("xmlDumpNotationTable"); break;
3157 case OP_HTML_NODE_DUMP:
3158 startOp("htmlNodeDump"); break;
3159 }
3160
3161 incStrIdx();
3162 buffer = xmlBufferCreate();
3163 xmlFuzzResetMallocFailed();
3164 node = getNode(0);
3165 doc = node ? node->doc : NULL;
3166 level = getInt(0);
3167 format = getInt(0);
3168 res = 0;
3169
3170 switch (op) {
3171 case OP_XML_NODE_DUMP:
3172 res = xmlNodeDump(buffer, doc, node, level, format);
3173 break;
3174 case OP_XML_NODE_BUF_GET_CONTENT:
3175 res = xmlNodeBufGetContent(buffer, node);
3176 break;
3177 case OP_XML_ATTR_SERIALIZE_TXT_CONTENT:
3178 if (node != NULL && node->type != XML_ATTRIBUTE_NODE)
3179 node = NULL;
3180 xmlAttrSerializeTxtContent(
3181 buffer, doc,
3182 (xmlAttrPtr) node,
3183 getStr(1));
3184 break;
3185 case OP_XML_DUMP_ELEMENT_DECL:
3186 if (node != NULL && node->type != XML_ELEMENT_DECL)
3187 node = NULL;
3188 xmlDumpElementDecl(buffer, (xmlElementPtr) node);
3189 break;
3190 case OP_XML_DUMP_ATTRIBUTE_DECL:
3191 if (node != NULL && node->type != XML_ATTRIBUTE_DECL)
3192 node = NULL;
3193 xmlDumpAttributeDecl(buffer, (xmlAttributePtr) node);
3194 break;
3195 case OP_XML_DUMP_NOTATION_DECL:
3196 /* TODO */
3197 break;
3198 case OP_XML_DUMP_ENTITY_DECL:
3199 if (node != NULL && node->type != XML_ENTITY_DECL)
3200 node = NULL;
3201 xmlDumpEntityDecl(buffer, (xmlEntityPtr) node);
3202 break;
3203 case OP_XML_DUMP_ELEMENT_TABLE: {
3204 xmlElementTablePtr table;
3205
3206 table = node != NULL && node->type == XML_DTD_NODE ?
3207 ((xmlDtdPtr) node)->elements :
3208 NULL;
3209 xmlDumpElementTable(buffer, table);
3210 break;
3211 }
3212 case OP_XML_DUMP_ATTRIBUTE_TABLE: {
3213 xmlAttributeTablePtr table;
3214
3215 table = node != NULL && node->type == XML_DTD_NODE ?
3216 ((xmlDtdPtr) node)->attributes :
3217 NULL;
3218 xmlDumpAttributeTable(buffer, table);
3219 break;
3220 }
3221 case OP_XML_DUMP_NOTATION_TABLE: {
3222 xmlNotationTablePtr table;
3223
3224 table = node != NULL && node->type == XML_DTD_NODE ?
3225 ((xmlDtdPtr) node)->notations :
3226 NULL;
3227 xmlDumpNotationTable(buffer, table);
3228 break;
3229 }
3230 case OP_XML_DUMP_ENTITIES_TABLE: {
3231 xmlEntitiesTablePtr table;
3232
3233 table = node != NULL && node->type == XML_DTD_NODE ?
3234 ((xmlDtdPtr) node)->entities :
3235 NULL;
3236 xmlDumpEntitiesTable(buffer, table);
3237 break;
3238 }
3239 #ifdef LIBXML_HTML_ENABLED
3240 case OP_HTML_NODE_DUMP:
3241 res = htmlNodeDump(buffer, doc, node);
3242 break;
3243 #endif /* LIBXML_HTML_ENABLED */
3244 }
3245
3246 dump = xmlBufferDetach(buffer);
3247 if (res == 0 && dump != NULL)
3248 oomReport = 0;
3249 moveStr(0, dump);
3250 xmlBufferFree(buffer);
3251 endOp();
3252 break;
3253 }
3254
3255 case OP_XML_SAVE_FILE_TO:
3256 case OP_XML_SAVE_FORMAT_FILE_TO:
3257 case OP_XML_NODE_DUMP_OUTPUT:
3258 case OP_HTML_DOC_CONTENT_DUMP_OUTPUT:
3259 case OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT:
3260 case OP_HTML_NODE_DUMP_OUTPUT:
3261 case OP_HTML_NODE_DUMP_FORMAT_OUTPUT: {
3262 xmlNodePtr node;
3263 xmlDocPtr doc;
3264 xmlOutputBufferPtr output;
3265 const char *encoding;
3266 int level, format, argsOk, res, closed;
3267
3268 switch (op) {
3269 case OP_XML_SAVE_FILE_TO:
3270 startOp("xmlSaveFileTo"); break;
3271 case OP_XML_SAVE_FORMAT_FILE_TO:
3272 startOp("xmlSaveFormatFileTo"); break;
3273 case OP_XML_NODE_DUMP_OUTPUT:
3274 startOp("xmlNodeDumpOutput"); break;
3275 case OP_HTML_DOC_CONTENT_DUMP_OUTPUT:
3276 startOp("htmlDocContentDumpOutput"); break;
3277 case OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT:
3278 startOp("htmlDocContentDumpFormatOutput"); break;
3279 case OP_HTML_NODE_DUMP_OUTPUT:
3280 startOp("htmlNodeDumpOutput"); break;
3281 case OP_HTML_NODE_DUMP_FORMAT_OUTPUT:
3282 startOp("htmlNodeDumpFormatOutput"); break;
3283 }
3284
3285 incStrIdx();
3286 output = xmlAllocOutputBuffer(NULL);
3287 xmlFuzzResetMallocFailed();
3288 node = getNode(0);
3289 doc = node ? node->doc : NULL;
3290 encoding = (const char *) getStr(1);
3291 level = getInt(0);
3292 format = getInt(0);
3293 argsOk = (output != NULL);
3294 res = 0;
3295 closed = 0;
3296
3297 switch (op) {
3298 case OP_XML_SAVE_FILE_TO:
3299 argsOk &= (doc != NULL);
3300 res = xmlSaveFileTo(output, doc, encoding);
3301 closed = 1;
3302 break;
3303 case OP_XML_SAVE_FORMAT_FILE_TO:
3304 argsOk &= (doc != NULL);
3305 res = xmlSaveFormatFileTo(output, doc, encoding, format);
3306 closed = 1;
3307 break;
3308 case OP_XML_NODE_DUMP_OUTPUT:
3309 argsOk &= (node != NULL);
3310 xmlNodeDumpOutput(output, doc, node, level, format,
3311 encoding);
3312 break;
3313 #ifdef LIBXML_HTML_ENABLED
3314 case OP_HTML_DOC_CONTENT_DUMP_OUTPUT:
3315 argsOk &= (doc != NULL);
3316 htmlDocContentDumpOutput(output, doc, encoding);
3317 break;
3318 case OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT:
3319 argsOk &= (doc != NULL);
3320 htmlDocContentDumpFormatOutput(output, doc, encoding,
3321 format);
3322 break;
3323 case OP_HTML_NODE_DUMP_OUTPUT:
3324 argsOk &= (node != NULL);
3325 htmlNodeDumpOutput(output, doc, node, encoding);
3326 break;
3327 case OP_HTML_NODE_DUMP_FORMAT_OUTPUT:
3328 argsOk &= (node != NULL);
3329 htmlNodeDumpFormatOutput(output, doc, node, encoding,
3330 format);
3331 break;
3332 #endif /* LIBXML_HTML_ENABLED */
3333 }
3334
3335 if (closed) {
3336 if (res >= 0)
3337 oomReport = 0;
3338 moveStr(0, NULL);
3339 } else {
3340 oomReport =
3341 (output != NULL &&
3342 output->error == XML_ERR_NO_MEMORY);
3343 if (argsOk && !output->error)
3344 copyStr(0, xmlBufContent(output->buffer));
3345 else
3346 moveStr(0, NULL);
3347 xmlOutputBufferClose(output);
3348 }
3349 endOp();
3350 break;
3351 }
3352 #endif /* LIBXML_OUTPUT_ENABLED */
3353
3354 case OP_XML_DOM_WRAP_RECONCILE_NAMESPACES: {
3355 xmlNodePtr node;
3356 int res;
3357
3358 startOp("xmlDOMWrapReconcileNamespaces");
3359 res = xmlDOMWrapReconcileNamespaces(
3360 NULL,
3361 node = getNode(0),
3362 getInt(0));
3363 oomReport =
3364 (node != NULL &&
3365 node->doc != NULL &&
3366 node->type == XML_ELEMENT_NODE &&
3367 res < 0);
3368 endOp();
3369 break;
3370 }
3371
3372 case OP_XML_DOM_WRAP_ADOPT_NODE: {
3373 xmlDOMWrapCtxtPtr ctxt;
3374 xmlDocPtr doc, destDoc, oldDoc;
3375 xmlNodePtr node, destParent, oldParent;
3376 int res;
3377
3378 startOp("xmlDOMWrapAdoptNode");
3379 ctxt = xmlDOMWrapNewCtxt();
3380 doc = getDoc(0);
3381 node = getNode(1);
3382 destDoc = getDoc(2);
3383 destParent = getNode(3);
3384
3385 if (!isValidChild(destParent, node))
3386 destParent = NULL;
3387
3388 oldParent = node ? node->parent : NULL;
3389 oldDoc = node ? node->doc : NULL;
3390
3391 res = xmlDOMWrapAdoptNode(
3392 ctxt,
3393 doc,
3394 node,
3395 destDoc,
3396 destParent,
3397 getInt(0));
3398 if (ctxt == NULL)
3399 oomReport = 1;
3400 else if (res == 0)
3401 oomReport = 0;
3402
3403 if (node != NULL) {
3404 /* Node can reference destParent's namespaces */
3405 if (destParent != NULL &&
3406 node->parent == NULL &&
3407 node->doc == destParent->doc) {
3408 if (node->type == XML_ATTRIBUTE_NODE) {
3409 xmlNodePtr prop;
3410
3411 /* Insert without removing duplicates */
3412 node->parent = destParent;
3413 prop = (xmlNodePtr) destParent->properties;
3414 node->next = prop;
3415 if (prop != NULL)
3416 prop->prev = node;
3417 destParent->properties = (xmlAttrPtr) node;
3418 } else if (node->type != XML_TEXT_NODE) {
3419 xmlAddChild(destParent, node);
3420 }
3421 }
3422
3423 /* Node can be unlinked and moved to a new document. */
3424 if (oldParent != NULL && node->parent != oldParent)
3425 dropNode(oldParent);
3426 else if (node->doc != oldDoc)
3427 dropNode((xmlNodePtr) oldDoc);
3428 }
3429
3430 xmlDOMWrapFreeCtxt(ctxt);
3431 endOp();
3432 break;
3433 }
3434
3435 case OP_XML_DOM_WRAP_REMOVE_NODE: {
3436 xmlDocPtr doc;
3437 xmlNodePtr node, oldParent;
3438 int res;
3439
3440 startOp("xmlDOMWrapRemoveNode");
3441 doc = getDoc(0);
3442 node = getNode(1);
3443 oldParent = node ? node->parent : NULL;
3444 res = xmlDOMWrapRemoveNode(NULL, doc, node, 0);
3445 oomReport =
3446 (node != NULL &&
3447 doc != NULL &&
3448 node->doc == doc &&
3449 res < 0);
3450 if (node != NULL && node->parent != oldParent) {
3451 if (fixNs(node) < 0)
3452 oomReport = 1;
3453 dropNode(oldParent);
3454 }
3455 endOp();
3456 break;
3457 }
3458
3459 case OP_XML_DOM_WRAP_CLONE_NODE: {
3460 xmlDOMWrapCtxtPtr ctxt;
3461 xmlDocPtr doc, destDoc;
3462 xmlNodePtr node, destParent, copy = NULL;
3463 int res;
3464
3465 startOp("xmlDOMWrapCloneNode");
3466 incNodeIdx();
3467 ctxt = xmlDOMWrapNewCtxt();
3468 doc = getDoc(1);
3469 node = getNode(2);
3470 destDoc = getDoc(3);
3471 destParent = getNode(4);
3472
3473 if (destParent != NULL &&
3474 node != NULL &&
3475 !isValidChildType(destParent, node->type))
3476 destParent = NULL;
3477
3478 /* xmlDOMWrapCloneNode returns a garbage node on error. */
3479 res = xmlDOMWrapCloneNode(
3480 ctxt,
3481 doc,
3482 node,
3483 ©,
3484 destDoc,
3485 destParent,
3486 getInt(0),
3487 0);
3488 if (ctxt == NULL)
3489 oomReport = 1;
3490 else if (res == 0)
3491 oomReport = 0;
3492 copy = checkCopy(copy);
3493
3494 /* Copy can reference destParent's namespaces */
3495 if (destParent != NULL && copy != NULL) {
3496 if (copy->type == XML_ATTRIBUTE_NODE) {
3497 xmlNodePtr prop;
3498
3499 /* Insert without removing duplicates */
3500 copy->parent = destParent;
3501 prop = (xmlNodePtr) destParent->properties;
3502 copy->next = prop;
3503 if (prop != NULL)
3504 prop->prev = copy;
3505 destParent->properties = (xmlAttrPtr) copy;
3506 } else if (copy->type != XML_TEXT_NODE) {
3507 xmlAddChild(destParent, copy);
3508 }
3509 }
3510
3511 xmlDOMWrapFreeCtxt(ctxt);
3512 setNode(0, copy);
3513 break;
3514 }
3515
3516 case OP_XML_CHILD_ELEMENT_COUNT:
3517 startOp("xmlChildElementCount");
3518 incIntIdx();
3519 setInt(0, xmlChildElementCount(getNode(0)));
3520 oomReport = 0;
3521 break;
3522
3523 case OP_XML_FIRST_ELEMENT_CHILD:
3524 startOp("xmlFirstElementChild");
3525 incNodeIdx();
3526 setNode(0, xmlFirstElementChild(getNode(1)));
3527 oomReport = 0;
3528 break;
3529
3530 case OP_XML_LAST_ELEMENT_CHILD:
3531 startOp("xmlLastElementChild");
3532 incNodeIdx();
3533 setNode(0, xmlLastElementChild(getNode(1)));
3534 oomReport = 0;
3535 break;
3536
3537 case OP_XML_NEXT_ELEMENT_SIBLING:
3538 startOp("xmlNextElementSibling");
3539 incNodeIdx();
3540 setNode(0, xmlNextElementSibling(getNode(1)));
3541 oomReport = 0;
3542 break;
3543
3544 case OP_XML_PREVIOUS_ELEMENT_SIBLING:
3545 startOp("xmlPreviousElementSibling");
3546 incNodeIdx();
3547 setNode(0, xmlPreviousElementSibling(getNode(1)));
3548 oomReport = 0;
3549 break;
3550
3551 default:
3552 break;
3553 }
3554
3555 xmlFuzzCheckMallocFailure(vars->opName, oomReport);
3556 }
3557
3558 for (i = 0; i < REG_MAX; i++)
3559 xmlFree(vars->strings[i]);
3560
3561 for (i = 0; i < REG_MAX; i++) {
3562 xmlNodePtr node = vars->nodes[i];
3563
3564 vars->nodes[i] = NULL;
3565 dropNode(node);
3566 }
3567
3568 xmlFuzzMemSetLimit(0);
3569 xmlFuzzDataCleanup();
3570 xmlResetLastError();
3571 return(0);
3572 }
3573
3574