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 oldDoc, 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 * Don't unlink DTD if it is the internal or external
2301 * subset of the document.
2302 */
2303 old = old ? old->parent : NULL;
2304 oldDoc = old ? old->doc : NULL;
2305 if (old != NULL &&
2306 (isDtdChild(old) ||
2307 (old->type == XML_DTD_NODE &&
2308 oldDoc != NULL &&
2309 ((xmlDtdPtr) old == oldDoc->intSubset ||
2310 (xmlDtdPtr) old == oldDoc->extSubset))))
2311 old = NULL;
2312 if (old != NULL && !isValidChild(old->parent, node))
2313 node = NULL;
2314
2315 oldParent = old ? old->parent : NULL;
2316 oldNodeParent = node ? node->parent : NULL;
2317 oldNodeDoc = node ? node->doc : NULL;
2318
2319 result = xmlReplaceNode(old, node);
2320 oomReport =
2321 (old != NULL && old->parent != NULL &&
2322 node != NULL &&
2323 old != node &&
2324 result == NULL);
2325
2326 if (old != NULL && old->parent != oldParent) {
2327 if (fixNs(old) < 0)
2328 oomReport = 1;
2329 }
2330 if (node == NULL) {
2331 /* Old node was unlinked */
2332 dropNode(oldParent);
2333 } else if (node->parent != oldNodeParent ||
2334 node->doc != oldNodeDoc) {
2335 if (fixNs(node) < 0)
2336 oomReport = 1;
2337 /* Drop old parent of new node */
2338 if (oldNodeParent != NULL)
2339 dropNode(oldNodeParent);
2340 else
2341 dropNode((xmlNodePtr) oldNodeDoc);
2342 }
2343 endOp();
2344 break;
2345 }
2346
2347 case OP_XML_ADD_CHILD:
2348 case OP_XML_ADD_SIBLING:
2349 case OP_XML_ADD_PREV_SIBLING:
2350 case OP_XML_ADD_NEXT_SIBLING: {
2351 xmlNodePtr target, parent, node, oldNodeParent, result;
2352 xmlDocPtr oldNodeDoc;
2353 int argsOk;
2354
2355 switch (op) {
2356 case OP_XML_ADD_CHILD:
2357 startOp("xmlAddChild"); break;
2358 case OP_XML_ADD_SIBLING:
2359 startOp("xmlAddSibling"); break;
2360 case OP_XML_ADD_PREV_SIBLING:
2361 startOp("xmlAddPrevSibling"); break;
2362 case OP_XML_ADD_NEXT_SIBLING:
2363 startOp("xmlAddNextSibling"); break;
2364 }
2365
2366 if (op == OP_XML_ADD_CHILD) {
2367 target = NULL;
2368 parent = getNode(0);
2369 } else {
2370 target = getNode(0);
2371 parent = target ? target->parent : NULL;
2372 }
2373 node = getNode(1);
2374
2375 /* Don't append to root node */
2376 if (target != NULL && parent == NULL)
2377 node = NULL;
2378
2379 /* Check tree structure */
2380 if (isDtdChild(node) ||
2381 !isValidChild(parent, node))
2382 node = NULL;
2383
2384 /* Attributes */
2385 if (node != NULL && node->type == XML_ATTRIBUTE_NODE) {
2386 if ((op == OP_XML_ADD_CHILD) ||
2387 ((target != NULL &&
2388 (target->type == XML_ATTRIBUTE_NODE)))) {
2389 xmlAttrPtr attr = xmlHasNsProp(parent, node->name,
2390 node->ns ? node->ns->href : NULL);
2391
2392 xmlFuzzResetMallocFailed();
2393 /* Attribute might be replaced */
2394 if (attr != NULL && attr != (xmlAttrPtr) node)
2395 removeChildren((xmlNodePtr) attr, 1);
2396 } else {
2397 target = NULL;
2398 }
2399 } else if (target != NULL &&
2400 target->type == XML_ATTRIBUTE_NODE) {
2401 node = NULL;
2402 }
2403
2404 oldNodeParent = node ? node->parent : NULL;
2405 oldNodeDoc = node ? node->doc : NULL;
2406 argsOk =
2407 (target != NULL &&
2408 node != NULL &&
2409 target != node);
2410
2411 switch (op) {
2412 case OP_XML_ADD_CHILD:
2413 argsOk = (parent != NULL && node != NULL);
2414 result = xmlAddChild(parent, node);
2415 break;
2416 case OP_XML_ADD_SIBLING:
2417 result = xmlAddSibling(target, node);
2418 break;
2419 case OP_XML_ADD_PREV_SIBLING:
2420 result = xmlAddPrevSibling(target, node);
2421 break;
2422 case OP_XML_ADD_NEXT_SIBLING:
2423 result = xmlAddNextSibling(target, node);
2424 break;
2425 }
2426 oomReport = (argsOk && result == NULL);
2427
2428 if (result != NULL && result != node) {
2429 /* Text node was merged */
2430 removeNode(node);
2431 checkContent(result);
2432 /* Drop old parent of node */
2433 if (oldNodeParent != NULL)
2434 dropNode(oldNodeParent);
2435 else
2436 dropNode((xmlNodePtr) oldNodeDoc);
2437 } else if (node != NULL &&
2438 (node->parent != oldNodeParent ||
2439 node->doc != oldNodeDoc)) {
2440 if (fixNs(node) < 0)
2441 oomReport = 1;
2442 /* Drop old parent of node */
2443 if (oldNodeParent != NULL)
2444 dropNode(oldNodeParent);
2445 else
2446 dropNode((xmlNodePtr) oldNodeDoc);
2447 }
2448
2449 endOp();
2450 break;
2451 }
2452
2453 case OP_XML_TEXT_MERGE: {
2454 xmlNodePtr first, second, parent = NULL, res;
2455 int argsOk;
2456
2457 startOp("xmlTextMerge");
2458 first = getNode(0);
2459 second = getNode(1);
2460 argsOk =
2461 (first != NULL && first->type == XML_TEXT_NODE &&
2462 second != NULL && second->type == XML_TEXT_NODE &&
2463 first != second &&
2464 first->name == second->name);
2465 if (argsOk) {
2466 if (second->parent != NULL)
2467 parent = second->parent;
2468 else
2469 parent = (xmlNodePtr) second->doc;
2470
2471 }
2472 res = xmlTextMerge(first, second);
2473 oomReport = (argsOk && res == NULL);
2474 if (res != NULL) {
2475 removeNode(second);
2476 dropNode(parent);
2477 checkContent(first);
2478 }
2479 endOp();
2480 break;
2481 }
2482
2483 case OP_XML_TEXT_CONCAT: {
2484 xmlNodePtr node;
2485 const xmlChar *text;
2486 int res;
2487
2488 startOp("xmlTextConcat");
2489 node = getNode(0);
2490 text = getStr(0);
2491 res = xmlTextConcat(
2492 node,
2493 text,
2494 xmlStrlen(text));
2495 oomReport = (isTextContentNode(node) && res < 0);
2496 checkContent(node);
2497 endOp();
2498 break;
2499 }
2500
2501 case OP_XML_STRING_GET_NODE_LIST: {
2502 xmlNodePtr list;
2503 const xmlChar *value;
2504
2505 startOp("xmlStringGetNodeList");
2506 list = xmlStringGetNodeList(
2507 getDoc(0),
2508 value = getStr(0));
2509 oomReport = (value != NULL && value[0] != 0 && list == NULL);
2510 xmlFreeNodeList(list);
2511 endOp();
2512 break;
2513 }
2514
2515 case OP_XML_STRING_LEN_GET_NODE_LIST: {
2516 xmlDocPtr doc;
2517 xmlNodePtr list;
2518 const xmlChar *value;
2519
2520 startOp("xmlStringLenGetNodeList");
2521 doc = getDoc(0);
2522 value = getStr(0);
2523 list = xmlStringLenGetNodeList(
2524 doc,
2525 value,
2526 xmlStrlen(value));
2527 oomReport = (value != NULL && value[0] != 0 && list == NULL);
2528 xmlFreeNodeList(list);
2529 endOp();
2530 break;
2531 }
2532
2533 case OP_XML_NODE_LIST_GET_STRING: {
2534 xmlDocPtr doc;
2535 xmlNodePtr list;
2536 xmlChar *string;
2537
2538 startOp("xmlNodeListGetString");
2539 incStrIdx();
2540 doc = getDoc(0);
2541 list = getNode(1);
2542 string = xmlNodeListGetString(
2543 doc,
2544 list,
2545 getInt(0));
2546 oomReport = (list != NULL && string == NULL);
2547 moveStr(0, string);
2548 endOp();
2549 break;
2550 }
2551
2552 case OP_XML_NODE_LIST_GET_RAW_STRING: {
2553 xmlDocPtr doc;
2554 xmlNodePtr list;
2555 xmlChar *string;
2556
2557 startOp("xmlNodeListGetRawString");
2558 incStrIdx();
2559 doc = getDoc(0);
2560 list = getNode(1);
2561 string = xmlNodeListGetRawString(
2562 doc,
2563 list,
2564 getInt(0));
2565 oomReport = (list != NULL && string == NULL);
2566 moveStr(0, string);
2567 endOp();
2568 break;
2569 }
2570
2571 case OP_XML_IS_XHTML:
2572 startOp("xmlIsXHTML");
2573 incIntIdx();
2574 setInt(0, xmlIsXHTML(
2575 getStr(0),
2576 getStr(1)));
2577 oomReport = 0;
2578 break;
2579
2580 case OP_XML_ADD_ELEMENT_DECL: {
2581 xmlElementPtr decl;
2582
2583 startOp("xmlAddElementDecl");
2584 incNodeIdx();
2585 decl = xmlAddElementDecl(
2586 NULL,
2587 getDtd(1),
2588 getStr(0),
2589 (xmlElementTypeVal) getInt(0),
2590 NULL);
2591 if (decl != NULL)
2592 oomReport = 0;
2593 setNode(0, (xmlNodePtr) decl);
2594 break;
2595 }
2596
2597 case OP_XML_ADD_ATTRIBUTE_DECL: {
2598 xmlAttributePtr decl;
2599
2600 startOp("xmlAddAttributeDecl");
2601 incNodeIdx();
2602 decl = xmlAddAttributeDecl(
2603 NULL,
2604 getDtd(1),
2605 getStr(0),
2606 getStr(1),
2607 getStr(2),
2608 (xmlAttributeType) getInt(0),
2609 (xmlAttributeDefault) getInt(1),
2610 getStr(3),
2611 NULL);
2612 if (decl != NULL)
2613 oomReport = 0;
2614 setNode(0, (xmlNodePtr) decl);
2615 break;
2616 }
2617
2618 case OP_XML_ADD_NOTATION_DECL: {
2619 xmlNotationPtr decl;
2620
2621 startOp("xmlAddNotationDecl");
2622 decl = xmlAddNotationDecl(
2623 NULL,
2624 getDtd(1),
2625 getStr(0),
2626 getStr(1),
2627 getStr(2));
2628 if (decl != NULL)
2629 oomReport = 0;
2630 endOp();
2631 break;
2632 }
2633
2634 case OP_XML_GET_DTD_ELEMENT_DESC: {
2635 xmlElementPtr elem;
2636
2637 startOp("xmlGetDtdElementDesc");
2638 incNodeIdx();
2639 elem = xmlGetDtdElementDesc(
2640 getDtd(1),
2641 getStr(0));
2642 if (elem != NULL)
2643 oomReport = 0;
2644 /*
2645 * Don't reference XML_ELEMENT_TYPE_UNDEFINED dummy
2646 * declarations.
2647 */
2648 if (elem != NULL && elem->parent == NULL)
2649 elem = NULL;
2650 setNode(0, (xmlNodePtr) elem);
2651 break;
2652 }
2653
2654 case OP_XML_GET_DTD_QELEMENT_DESC: {
2655 xmlElementPtr elem;
2656
2657 startOp("xmlGetDtdQElementDesc");
2658 incNodeIdx();
2659 elem = xmlGetDtdQElementDesc(
2660 getDtd(1),
2661 getStr(0),
2662 getStr(1));
2663 oomReport = 0;
2664 if (elem != NULL && elem->parent == NULL)
2665 elem = NULL;
2666 setNode(0, (xmlNodePtr) elem);
2667 break;
2668 }
2669
2670 case OP_XML_GET_DTD_ATTR_DESC: {
2671 xmlAttributePtr decl;
2672
2673 startOp("xmlGetDtdAttrDesc");
2674 incNodeIdx();
2675 decl = xmlGetDtdAttrDesc(
2676 getDtd(1),
2677 getStr(0),
2678 getStr(1));
2679 if (decl != NULL)
2680 oomReport = 0;
2681 setNode(0, (xmlNodePtr) decl);
2682 break;
2683 }
2684
2685 case OP_XML_GET_DTD_QATTR_DESC: {
2686 xmlAttributePtr decl;
2687
2688 startOp("xmlGetDtdQAttrDesc");
2689 incNodeIdx();
2690 decl = xmlGetDtdQAttrDesc(
2691 getDtd(1),
2692 getStr(0),
2693 getStr(1),
2694 getStr(2));
2695 oomReport = 0;
2696 setNode(0, (xmlNodePtr) decl);
2697 break;
2698 }
2699
2700 case OP_XML_GET_DTD_NOTATION_DESC:
2701 startOp("xmlGetDtdNotationDesc");
2702 xmlGetDtdNotationDesc(
2703 getDtd(1),
2704 getStr(0));
2705 oomReport = 0;
2706 endOp();
2707 break;
2708
2709 case OP_XML_ADD_ID:
2710 startOp("xmlAddID");
2711 xmlAddID(
2712 NULL,
2713 getDoc(0),
2714 getStr(0),
2715 getAttr(1));
2716 endOp();
2717 break;
2718
2719 case OP_XML_ADD_ID_SAFE: {
2720 int res;
2721
2722 startOp("xmlAddIDSafe");
2723 res = xmlAddIDSafe(
2724 getAttr(0),
2725 getStr(0));
2726 oomReport = (res < 0);
2727 endOp();
2728 break;
2729 }
2730
2731 case OP_XML_GET_ID:
2732 startOp("xmlGetID");
2733 incNodeIdx();
2734 setNode(0, (xmlNodePtr) xmlGetID(
2735 getDoc(1),
2736 getStr(0)));
2737 oomReport = 0;
2738 break;
2739
2740 case OP_XML_IS_ID: {
2741 int res;
2742
2743 startOp("xmlIsID");
2744 res = xmlIsID(
2745 getDoc(2),
2746 getNode(1),
2747 getAttr(0));
2748 oomReport = (res < 0);
2749 endOp();
2750 break;
2751 }
2752
2753 case OP_XML_REMOVE_ID:
2754 startOp("xmlRemoveID");
2755 xmlRemoveID(
2756 getDoc(1),
2757 getAttr(0));
2758 oomReport = 0;
2759 endOp();
2760 break;
2761
2762 case OP_XML_ADD_REF: {
2763 xmlDocPtr doc;
2764 xmlAttrPtr attr;
2765 xmlRefPtr ref;
2766 const xmlChar *value;
2767
2768 startOp("xmlAddRef");
2769 ref = xmlAddRef(
2770 NULL,
2771 doc = getDoc(0),
2772 value = getStr(0),
2773 attr = getAttr(1));
2774 oomReport =
2775 (doc != NULL &&
2776 value != NULL &&
2777 attr != NULL &&
2778 ref == NULL);
2779 endOp();
2780 break;
2781 }
2782
2783 case OP_XML_GET_REFS:
2784 startOp("xmlGetRefs");
2785 xmlGetRefs(
2786 getDoc(1),
2787 getStr(0));
2788 oomReport = 0;
2789 endOp();
2790 break;
2791
2792 case OP_XML_IS_REF:
2793 startOp("xmlIsRef");
2794 xmlIsRef(
2795 getDoc(2),
2796 getNode(1),
2797 getAttr(0));
2798 oomReport = 0;
2799 endOp();
2800 break;
2801
2802 case OP_XML_REMOVE_REF: {
2803 int res;
2804
2805 startOp("xmlRemoveRef");
2806 res = xmlRemoveRef(
2807 getDoc(1),
2808 getAttr(0));
2809 if (res == 0)
2810 oomReport = 0;
2811 endOp();
2812 break;
2813 }
2814
2815 case OP_XML_NEW_ENTITY: {
2816 xmlDocPtr doc;
2817 xmlEntityPtr ent;
2818
2819 startOp("xmlNewEntity");
2820 incNodeIdx();
2821 ent = xmlNewEntity(
2822 doc = getDoc(1),
2823 getStr(0),
2824 getInt(0),
2825 getStr(1),
2826 getStr(2),
2827 getStr(3));
2828 if (ent != NULL)
2829 oomReport = 0;
2830 if (doc == NULL || doc->intSubset == NULL) {
2831 xmlFreeEntity(ent);
2832 ent = NULL;
2833 }
2834 setNode(0, (xmlNodePtr) ent);
2835 break;
2836 }
2837
2838 case OP_XML_ADD_ENTITY: {
2839 xmlEntityPtr ent;
2840 int res;
2841
2842 startOp("xmlAddEntity");
2843 incNodeIdx();
2844 res = xmlAddEntity(
2845 getDoc(1),
2846 getInt(0),
2847 getStr(0),
2848 getInt(1),
2849 getStr(1),
2850 getStr(2),
2851 getStr(3),
2852 &ent);
2853 oomReport = (res == XML_ERR_NO_MEMORY);
2854 setNode(0, (xmlNodePtr) ent);
2855 break;
2856 }
2857
2858 case OP_XML_ADD_DOC_ENTITY: {
2859 xmlEntityPtr ent;
2860
2861 startOp("xmlAddDocEntity");
2862 incNodeIdx();
2863 ent = xmlAddDocEntity(
2864 getDoc(1),
2865 getStr(0),
2866 getInt(1),
2867 getStr(1),
2868 getStr(2),
2869 getStr(3));
2870 if (ent != NULL)
2871 oomReport = 0;
2872 setNode(0, (xmlNodePtr) ent);
2873 break;
2874 }
2875
2876 case OP_XML_ADD_DTD_ENTITY: {
2877 xmlEntityPtr ent;
2878
2879 startOp("xmlAddDtdEntity");
2880 incNodeIdx();
2881 ent = xmlAddDtdEntity(
2882 getDoc(1),
2883 getStr(0),
2884 getInt(1),
2885 getStr(1),
2886 getStr(2),
2887 getStr(3));
2888 setNode(0, (xmlNodePtr) ent);
2889 break;
2890 }
2891
2892 case OP_XML_GET_PREDEFINED_ENTITY:
2893 startOp("xmlGetPredefinedEntity");
2894 incNodeIdx();
2895 setNode(0, (xmlNodePtr) xmlGetPredefinedEntity(
2896 getStr(0)));
2897 oomReport = 0;
2898 break;
2899
2900 case OP_XML_GET_DOC_ENTITY:
2901 startOp("xmlGetDocEntity");
2902 incNodeIdx();
2903 setNode(0, (xmlNodePtr) xmlGetDocEntity(
2904 getDoc(1),
2905 getStr(0)));
2906 oomReport = 0;
2907 break;
2908
2909 case OP_XML_GET_DTD_ENTITY:
2910 startOp("xmlGetDtdEntity");
2911 incNodeIdx();
2912 setNode(0, (xmlNodePtr) xmlGetDtdEntity(
2913 getDoc(1),
2914 getStr(0)));
2915 oomReport = 0;
2916 break;
2917
2918 case OP_XML_GET_PARAMETER_ENTITY:
2919 startOp("xmlGetParameterEntity");
2920 incNodeIdx();
2921 setNode(0, (xmlNodePtr) xmlGetParameterEntity(
2922 getDoc(1),
2923 getStr(0)));
2924 oomReport = 0;
2925 break;
2926
2927 case OP_XML_ENCODE_ENTITIES_REENTRANT: {
2928 const xmlChar *string;
2929 xmlChar *encoded;
2930
2931 startOp("xmlEncodeEntitiesReentrant");
2932 incStrIdx();
2933 encoded = xmlEncodeEntitiesReentrant(
2934 getDoc(0),
2935 string = getStr(1));
2936 oomReport = (string != NULL && encoded == NULL);
2937 moveStr(0, encoded);
2938 endOp();
2939 break;
2940 }
2941
2942 case OP_XML_ENCODE_SPECIAL_CHARS: {
2943 const xmlChar *string;
2944 xmlChar *encoded;
2945
2946 startOp("xmlEncodespecialChars");
2947 incStrIdx();
2948 encoded = xmlEncodeSpecialChars(
2949 getDoc(0),
2950 string = getStr(1));
2951 oomReport = (string != NULL && encoded == NULL);
2952 moveStr(0, encoded);
2953 endOp();
2954 break;
2955 }
2956
2957 #ifdef LIBXML_HTML_ENABLED
2958 case OP_HTML_NEW_DOC: {
2959 htmlDocPtr doc;
2960
2961 startOp("htmlNewDoc");
2962 incNodeIdx();
2963 doc = htmlNewDoc(
2964 getStr(0),
2965 getStr(1));
2966 oomReport = (doc == NULL);
2967 setNode(0, (xmlNodePtr) doc);
2968 break;
2969 }
2970
2971 case OP_HTML_NEW_DOC_NO_DTD: {
2972 htmlDocPtr doc;
2973
2974 startOp("htmlNewDocNoDtD");
2975 incNodeIdx();
2976 doc = htmlNewDocNoDtD(
2977 getStr(0),
2978 getStr(1));
2979 oomReport = (doc == NULL);
2980 setNode(0, (xmlNodePtr) doc);
2981 break;
2982 }
2983
2984 case OP_HTML_GET_META_ENCODING: {
2985 const xmlChar *encoding;
2986
2987 startOp("htmlGetMetaEncoding");
2988 incStrIdx();
2989 encoding = htmlGetMetaEncoding(getDoc(0));
2990 if (encoding != NULL)
2991 oomReport = 0;
2992 copyStr(0, encoding);
2993 break;
2994 }
2995
2996 case OP_HTML_SET_META_ENCODING:
2997 /* TODO (can destroy inner text) */
2998 break;
2999
3000 case OP_HTML_IS_BOOLEAN_ATTR:
3001 startOp("htmlIsBooleanAttr");
3002 htmlIsBooleanAttr(getStr(0));
3003 oomReport = 0;
3004 endOp();
3005 break;
3006 #endif
3007
3008 #ifdef LIBXML_VALID_ENABLED
3009 case OP_VALIDATE: {
3010 xmlNodePtr node;
3011 int type;
3012 int res = 1;
3013
3014 startOp("validate");
3015 incIntIdx();
3016 node = getNode(0);
3017 type = node ? node->type : 0;
3018 xmlValidCtxtPtr vctxt = xmlNewValidCtxt();
3019 xmlFuzzResetMallocFailed();
3020
3021 switch (type) {
3022 case XML_DOCUMENT_NODE:
3023 case XML_HTML_DOCUMENT_NODE:
3024 res = xmlValidateDocument(vctxt, (xmlDocPtr) node);
3025 break;
3026 case XML_ELEMENT_DECL:
3027 res = xmlValidateElementDecl(vctxt, node->doc,
3028 (xmlElementPtr) node);
3029 break;
3030 case XML_ATTRIBUTE_DECL:
3031 res = xmlValidateAttributeDecl(vctxt, node->doc,
3032 (xmlAttributePtr) node);
3033 break;
3034 case XML_ELEMENT_NODE:
3035 res = xmlValidateElement(vctxt, node->doc, node);
3036 break;
3037 default:
3038 break;
3039 }
3040
3041 if (res != 0)
3042 oomReport = 0;
3043 xmlFreeValidCtxt(vctxt);
3044 setInt(0, res);
3045 endOp();
3046 break;
3047 }
3048
3049 case OP_XML_VALIDATE_DTD: {
3050 xmlValidCtxtPtr vctxt;
3051 int res;
3052
3053 startOp("xmlValidateDtd");
3054 incIntIdx();
3055 vctxt = xmlNewValidCtxt();
3056 res = xmlValidateDtd(
3057 vctxt,
3058 getDoc(0),
3059 getDtd(1));
3060 if (res != 0)
3061 oomReport = 0;
3062 xmlFreeValidCtxt(vctxt);
3063 setInt(0, res);
3064 endOp();
3065 break;
3066 }
3067 #endif /* LIBXML_VALID_ENABLED */
3068
3069 #ifdef LIBXML_OUTPUT_ENABLED
3070 case OP_XML_DOC_DUMP_MEMORY:
3071 case OP_XML_DOC_DUMP_MEMORY_ENC:
3072 case OP_XML_DOC_DUMP_FORMAT_MEMORY:
3073 case OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC:
3074 case OP_HTML_DOC_DUMP_MEMORY:
3075 case OP_HTML_DOC_DUMP_MEMORY_FORMAT: {
3076 xmlDocPtr doc;
3077 xmlChar *out = NULL;
3078 int outSize = 0;
3079
3080 switch (op) {
3081 case OP_XML_DOC_DUMP_MEMORY:
3082 startOp("xmlDocDumpMemory"); break;
3083 case OP_XML_DOC_DUMP_MEMORY_ENC:
3084 startOp("xmlDocDumpMemoryEnc"); break;
3085 case OP_XML_DOC_DUMP_FORMAT_MEMORY:
3086 startOp("xmlDocDumpFormatMemory"); break;
3087 case OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC:
3088 startOp("xmlDocDumpFormatMemoryEnc"); break;
3089 case OP_HTML_DOC_DUMP_MEMORY:
3090 startOp("htmlDocDumpMemory"); break;
3091 case OP_HTML_DOC_DUMP_MEMORY_FORMAT:
3092 startOp("htmlDocDumpMemoryFormat"); break;
3093 }
3094
3095 incStrIdx();
3096 doc = getDoc(0);
3097
3098 switch (op) {
3099 case OP_XML_DOC_DUMP_MEMORY:
3100 xmlDocDumpMemory(doc, &out, &outSize);
3101 break;
3102 case OP_XML_DOC_DUMP_MEMORY_ENC:
3103 xmlDocDumpMemoryEnc(doc, &out, &outSize,
3104 (const char *) getStr(1));
3105 break;
3106 case OP_XML_DOC_DUMP_FORMAT_MEMORY:
3107 xmlDocDumpFormatMemory(doc, &out, &outSize,
3108 getInt(0));
3109 break;
3110 case OP_XML_DOC_DUMP_FORMAT_MEMORY_ENC:
3111 xmlDocDumpFormatMemoryEnc(doc, &out, &outSize,
3112 (const char *) getStr(1),
3113 getInt(0));
3114 break;
3115 #ifdef LIBXML_HTML_ENABLED
3116 case OP_HTML_DOC_DUMP_MEMORY:
3117 htmlDocDumpMemory(doc, &out, &outSize);
3118 break;
3119 case OP_HTML_DOC_DUMP_MEMORY_FORMAT:
3120 htmlDocDumpMemoryFormat(doc, &out, &outSize,
3121 getInt(0));
3122 break;
3123 #endif /* LIBXML_HTML_ENABLED */
3124 }
3125
3126 /* Could be an unknown encoding */
3127 if (out != NULL)
3128 oomReport = 0;
3129 moveStr(0, out);
3130 endOp();
3131 break;
3132 }
3133
3134 case OP_XML_NODE_DUMP:
3135 case OP_XML_NODE_BUF_GET_CONTENT:
3136 case OP_XML_ATTR_SERIALIZE_TXT_CONTENT:
3137 case OP_XML_DUMP_ELEMENT_DECL:
3138 case OP_XML_DUMP_ELEMENT_TABLE:
3139 case OP_XML_DUMP_ATTRIBUTE_DECL:
3140 case OP_XML_DUMP_ATTRIBUTE_TABLE:
3141 case OP_XML_DUMP_ENTITY_DECL:
3142 case OP_XML_DUMP_ENTITIES_TABLE:
3143 case OP_XML_DUMP_NOTATION_DECL:
3144 case OP_XML_DUMP_NOTATION_TABLE:
3145 case OP_HTML_NODE_DUMP: {
3146 xmlNodePtr node;
3147 xmlDocPtr doc;
3148 xmlBufferPtr buffer;
3149 xmlChar *dump;
3150 int level, format, res;
3151
3152 switch (op) {
3153 case OP_XML_NODE_DUMP:
3154 startOp("xmlNodeDump"); break;
3155 case OP_XML_NODE_BUF_GET_CONTENT:
3156 startOp("xmlNodeBufGetContent"); break;
3157 case OP_XML_ATTR_SERIALIZE_TXT_CONTENT:
3158 startOp("xmlAttrSerializeTxtContent"); break;
3159 case OP_XML_DUMP_ELEMENT_DECL:
3160 startOp("xmlDumpElementDecl"); break;
3161 case OP_XML_DUMP_ELEMENT_TABLE:
3162 startOp("xmlDumpElementTable"); break;
3163 case OP_XML_DUMP_ATTRIBUTE_DECL:
3164 startOp("xmlDumpAttributeDecl"); break;
3165 case OP_XML_DUMP_ATTRIBUTE_TABLE:
3166 startOp("xmlDumpAttributeTable"); break;
3167 case OP_XML_DUMP_ENTITY_DECL:
3168 startOp("xmlDumpEntityDecl"); break;
3169 case OP_XML_DUMP_ENTITIES_TABLE:
3170 startOp("xmlDumpEntitiesTable"); break;
3171 case OP_XML_DUMP_NOTATION_DECL:
3172 startOp("xmlDumpNotationDecl"); break;
3173 case OP_XML_DUMP_NOTATION_TABLE:
3174 startOp("xmlDumpNotationTable"); break;
3175 case OP_HTML_NODE_DUMP:
3176 startOp("htmlNodeDump"); break;
3177 }
3178
3179 incStrIdx();
3180 buffer = xmlBufferCreate();
3181 xmlFuzzResetMallocFailed();
3182 node = getNode(0);
3183 doc = node ? node->doc : NULL;
3184 level = getInt(0);
3185 format = getInt(0);
3186 res = 0;
3187
3188 switch (op) {
3189 case OP_XML_NODE_DUMP:
3190 res = xmlNodeDump(buffer, doc, node, level, format);
3191 break;
3192 case OP_XML_NODE_BUF_GET_CONTENT:
3193 res = xmlNodeBufGetContent(buffer, node);
3194 break;
3195 case OP_XML_ATTR_SERIALIZE_TXT_CONTENT:
3196 if (node != NULL && node->type != XML_ATTRIBUTE_NODE)
3197 node = NULL;
3198 xmlAttrSerializeTxtContent(
3199 buffer, doc,
3200 (xmlAttrPtr) node,
3201 getStr(1));
3202 break;
3203 case OP_XML_DUMP_ELEMENT_DECL:
3204 if (node != NULL && node->type != XML_ELEMENT_DECL)
3205 node = NULL;
3206 xmlDumpElementDecl(buffer, (xmlElementPtr) node);
3207 break;
3208 case OP_XML_DUMP_ATTRIBUTE_DECL:
3209 if (node != NULL && node->type != XML_ATTRIBUTE_DECL)
3210 node = NULL;
3211 xmlDumpAttributeDecl(buffer, (xmlAttributePtr) node);
3212 break;
3213 case OP_XML_DUMP_NOTATION_DECL:
3214 /* TODO */
3215 break;
3216 case OP_XML_DUMP_ENTITY_DECL:
3217 if (node != NULL && node->type != XML_ENTITY_DECL)
3218 node = NULL;
3219 xmlDumpEntityDecl(buffer, (xmlEntityPtr) node);
3220 break;
3221 case OP_XML_DUMP_ELEMENT_TABLE: {
3222 xmlElementTablePtr table;
3223
3224 table = node != NULL && node->type == XML_DTD_NODE ?
3225 ((xmlDtdPtr) node)->elements :
3226 NULL;
3227 xmlDumpElementTable(buffer, table);
3228 break;
3229 }
3230 case OP_XML_DUMP_ATTRIBUTE_TABLE: {
3231 xmlAttributeTablePtr table;
3232
3233 table = node != NULL && node->type == XML_DTD_NODE ?
3234 ((xmlDtdPtr) node)->attributes :
3235 NULL;
3236 xmlDumpAttributeTable(buffer, table);
3237 break;
3238 }
3239 case OP_XML_DUMP_NOTATION_TABLE: {
3240 xmlNotationTablePtr table;
3241
3242 table = node != NULL && node->type == XML_DTD_NODE ?
3243 ((xmlDtdPtr) node)->notations :
3244 NULL;
3245 xmlDumpNotationTable(buffer, table);
3246 break;
3247 }
3248 case OP_XML_DUMP_ENTITIES_TABLE: {
3249 xmlEntitiesTablePtr table;
3250
3251 table = node != NULL && node->type == XML_DTD_NODE ?
3252 ((xmlDtdPtr) node)->entities :
3253 NULL;
3254 xmlDumpEntitiesTable(buffer, table);
3255 break;
3256 }
3257 #ifdef LIBXML_HTML_ENABLED
3258 case OP_HTML_NODE_DUMP:
3259 res = htmlNodeDump(buffer, doc, node);
3260 break;
3261 #endif /* LIBXML_HTML_ENABLED */
3262 }
3263
3264 dump = xmlBufferDetach(buffer);
3265 if (res == 0 && dump != NULL)
3266 oomReport = 0;
3267 moveStr(0, dump);
3268 xmlBufferFree(buffer);
3269 endOp();
3270 break;
3271 }
3272
3273 case OP_XML_SAVE_FILE_TO:
3274 case OP_XML_SAVE_FORMAT_FILE_TO:
3275 case OP_XML_NODE_DUMP_OUTPUT:
3276 case OP_HTML_DOC_CONTENT_DUMP_OUTPUT:
3277 case OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT:
3278 case OP_HTML_NODE_DUMP_OUTPUT:
3279 case OP_HTML_NODE_DUMP_FORMAT_OUTPUT: {
3280 xmlNodePtr node;
3281 xmlDocPtr doc;
3282 xmlOutputBufferPtr output;
3283 const char *encoding;
3284 int level, format, argsOk, res, closed;
3285
3286 switch (op) {
3287 case OP_XML_SAVE_FILE_TO:
3288 startOp("xmlSaveFileTo"); break;
3289 case OP_XML_SAVE_FORMAT_FILE_TO:
3290 startOp("xmlSaveFormatFileTo"); break;
3291 case OP_XML_NODE_DUMP_OUTPUT:
3292 startOp("xmlNodeDumpOutput"); break;
3293 case OP_HTML_DOC_CONTENT_DUMP_OUTPUT:
3294 startOp("htmlDocContentDumpOutput"); break;
3295 case OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT:
3296 startOp("htmlDocContentDumpFormatOutput"); break;
3297 case OP_HTML_NODE_DUMP_OUTPUT:
3298 startOp("htmlNodeDumpOutput"); break;
3299 case OP_HTML_NODE_DUMP_FORMAT_OUTPUT:
3300 startOp("htmlNodeDumpFormatOutput"); break;
3301 }
3302
3303 incStrIdx();
3304 output = xmlAllocOutputBuffer(NULL);
3305 xmlFuzzResetMallocFailed();
3306 node = getNode(0);
3307 doc = node ? node->doc : NULL;
3308 encoding = (const char *) getStr(1);
3309 level = getInt(0);
3310 format = getInt(0);
3311 argsOk = (output != NULL);
3312 res = 0;
3313 closed = 0;
3314
3315 switch (op) {
3316 case OP_XML_SAVE_FILE_TO:
3317 argsOk &= (doc != NULL);
3318 res = xmlSaveFileTo(output, doc, encoding);
3319 closed = 1;
3320 break;
3321 case OP_XML_SAVE_FORMAT_FILE_TO:
3322 argsOk &= (doc != NULL);
3323 res = xmlSaveFormatFileTo(output, doc, encoding, format);
3324 closed = 1;
3325 break;
3326 case OP_XML_NODE_DUMP_OUTPUT:
3327 argsOk &= (node != NULL);
3328 xmlNodeDumpOutput(output, doc, node, level, format,
3329 encoding);
3330 break;
3331 #ifdef LIBXML_HTML_ENABLED
3332 case OP_HTML_DOC_CONTENT_DUMP_OUTPUT:
3333 argsOk &= (doc != NULL);
3334 htmlDocContentDumpOutput(output, doc, encoding);
3335 break;
3336 case OP_HTML_DOC_CONTENT_DUMP_FORMAT_OUTPUT:
3337 argsOk &= (doc != NULL);
3338 htmlDocContentDumpFormatOutput(output, doc, encoding,
3339 format);
3340 break;
3341 case OP_HTML_NODE_DUMP_OUTPUT:
3342 argsOk &= (node != NULL);
3343 htmlNodeDumpOutput(output, doc, node, encoding);
3344 break;
3345 case OP_HTML_NODE_DUMP_FORMAT_OUTPUT:
3346 argsOk &= (node != NULL);
3347 htmlNodeDumpFormatOutput(output, doc, node, encoding,
3348 format);
3349 break;
3350 #endif /* LIBXML_HTML_ENABLED */
3351 }
3352
3353 if (closed) {
3354 if (res >= 0)
3355 oomReport = 0;
3356 moveStr(0, NULL);
3357 } else {
3358 oomReport =
3359 (output != NULL &&
3360 output->error == XML_ERR_NO_MEMORY);
3361 if (argsOk && !output->error)
3362 copyStr(0, xmlBufContent(output->buffer));
3363 else
3364 moveStr(0, NULL);
3365 xmlOutputBufferClose(output);
3366 }
3367 endOp();
3368 break;
3369 }
3370 #endif /* LIBXML_OUTPUT_ENABLED */
3371
3372 case OP_XML_DOM_WRAP_RECONCILE_NAMESPACES: {
3373 xmlNodePtr node;
3374 int res;
3375
3376 startOp("xmlDOMWrapReconcileNamespaces");
3377 res = xmlDOMWrapReconcileNamespaces(
3378 NULL,
3379 node = getNode(0),
3380 getInt(0));
3381 oomReport =
3382 (node != NULL &&
3383 node->doc != NULL &&
3384 node->type == XML_ELEMENT_NODE &&
3385 res < 0);
3386 endOp();
3387 break;
3388 }
3389
3390 case OP_XML_DOM_WRAP_ADOPT_NODE: {
3391 xmlDOMWrapCtxtPtr ctxt;
3392 xmlDocPtr doc, destDoc, oldDoc;
3393 xmlNodePtr node, destParent, oldParent;
3394 int res;
3395
3396 startOp("xmlDOMWrapAdoptNode");
3397 ctxt = xmlDOMWrapNewCtxt();
3398 doc = getDoc(0);
3399 node = getNode(1);
3400 destDoc = getDoc(2);
3401 destParent = getNode(3);
3402
3403 if (!isValidChild(destParent, node))
3404 destParent = NULL;
3405
3406 oldParent = node ? node->parent : NULL;
3407 oldDoc = node ? node->doc : NULL;
3408
3409 res = xmlDOMWrapAdoptNode(
3410 ctxt,
3411 doc,
3412 node,
3413 destDoc,
3414 destParent,
3415 getInt(0));
3416 if (ctxt == NULL)
3417 oomReport = 1;
3418 else if (res == 0)
3419 oomReport = 0;
3420
3421 if (node != NULL) {
3422 /* Node can reference destParent's namespaces */
3423 if (destParent != NULL &&
3424 node->parent == NULL &&
3425 node->doc == destParent->doc) {
3426 if (node->type == XML_ATTRIBUTE_NODE) {
3427 xmlNodePtr prop;
3428
3429 /* Insert without removing duplicates */
3430 node->parent = destParent;
3431 prop = (xmlNodePtr) destParent->properties;
3432 node->next = prop;
3433 if (prop != NULL)
3434 prop->prev = node;
3435 destParent->properties = (xmlAttrPtr) node;
3436 } else if (node->type != XML_TEXT_NODE) {
3437 xmlAddChild(destParent, node);
3438 }
3439 }
3440
3441 /* Node can be unlinked and moved to a new document. */
3442 if (oldParent != NULL && node->parent != oldParent)
3443 dropNode(oldParent);
3444 else if (node->doc != oldDoc)
3445 dropNode((xmlNodePtr) oldDoc);
3446 }
3447
3448 xmlDOMWrapFreeCtxt(ctxt);
3449 endOp();
3450 break;
3451 }
3452
3453 case OP_XML_DOM_WRAP_REMOVE_NODE: {
3454 xmlDocPtr doc;
3455 xmlNodePtr node, oldParent;
3456 int res;
3457
3458 startOp("xmlDOMWrapRemoveNode");
3459 doc = getDoc(0);
3460 node = getNode(1);
3461 oldParent = node ? node->parent : NULL;
3462 res = xmlDOMWrapRemoveNode(NULL, doc, node, 0);
3463 oomReport =
3464 (node != NULL &&
3465 doc != NULL &&
3466 node->doc == doc &&
3467 res < 0);
3468 if (node != NULL && node->parent != oldParent) {
3469 if (fixNs(node) < 0)
3470 oomReport = 1;
3471 dropNode(oldParent);
3472 }
3473 endOp();
3474 break;
3475 }
3476
3477 case OP_XML_DOM_WRAP_CLONE_NODE: {
3478 xmlDOMWrapCtxtPtr ctxt;
3479 xmlDocPtr doc, destDoc;
3480 xmlNodePtr node, destParent, copy = NULL;
3481 int res;
3482
3483 startOp("xmlDOMWrapCloneNode");
3484 incNodeIdx();
3485 ctxt = xmlDOMWrapNewCtxt();
3486 doc = getDoc(1);
3487 node = getNode(2);
3488 destDoc = getDoc(3);
3489 destParent = getNode(4);
3490
3491 if (destParent != NULL &&
3492 node != NULL &&
3493 !isValidChildType(destParent, node->type))
3494 destParent = NULL;
3495
3496 /* xmlDOMWrapCloneNode returns a garbage node on error. */
3497 res = xmlDOMWrapCloneNode(
3498 ctxt,
3499 doc,
3500 node,
3501 ©,
3502 destDoc,
3503 destParent,
3504 getInt(0),
3505 0);
3506 if (ctxt == NULL)
3507 oomReport = 1;
3508 else if (res == 0)
3509 oomReport = 0;
3510 copy = checkCopy(copy);
3511
3512 /* Copy can reference destParent's namespaces */
3513 if (destParent != NULL && copy != NULL) {
3514 if (copy->type == XML_ATTRIBUTE_NODE) {
3515 xmlNodePtr prop;
3516
3517 /* Insert without removing duplicates */
3518 copy->parent = destParent;
3519 prop = (xmlNodePtr) destParent->properties;
3520 copy->next = prop;
3521 if (prop != NULL)
3522 prop->prev = copy;
3523 destParent->properties = (xmlAttrPtr) copy;
3524 } else if (copy->type != XML_TEXT_NODE) {
3525 xmlAddChild(destParent, copy);
3526 }
3527 }
3528
3529 xmlDOMWrapFreeCtxt(ctxt);
3530 setNode(0, copy);
3531 break;
3532 }
3533
3534 case OP_XML_CHILD_ELEMENT_COUNT:
3535 startOp("xmlChildElementCount");
3536 incIntIdx();
3537 setInt(0, xmlChildElementCount(getNode(0)));
3538 oomReport = 0;
3539 break;
3540
3541 case OP_XML_FIRST_ELEMENT_CHILD:
3542 startOp("xmlFirstElementChild");
3543 incNodeIdx();
3544 setNode(0, xmlFirstElementChild(getNode(1)));
3545 oomReport = 0;
3546 break;
3547
3548 case OP_XML_LAST_ELEMENT_CHILD:
3549 startOp("xmlLastElementChild");
3550 incNodeIdx();
3551 setNode(0, xmlLastElementChild(getNode(1)));
3552 oomReport = 0;
3553 break;
3554
3555 case OP_XML_NEXT_ELEMENT_SIBLING:
3556 startOp("xmlNextElementSibling");
3557 incNodeIdx();
3558 setNode(0, xmlNextElementSibling(getNode(1)));
3559 oomReport = 0;
3560 break;
3561
3562 case OP_XML_PREVIOUS_ELEMENT_SIBLING:
3563 startOp("xmlPreviousElementSibling");
3564 incNodeIdx();
3565 setNode(0, xmlPreviousElementSibling(getNode(1)));
3566 oomReport = 0;
3567 break;
3568
3569 default:
3570 break;
3571 }
3572
3573 xmlFuzzCheckMallocFailure(vars->opName, oomReport);
3574 }
3575
3576 for (i = 0; i < REG_MAX; i++)
3577 xmlFree(vars->strings[i]);
3578
3579 for (i = 0; i < REG_MAX; i++) {
3580 xmlNodePtr node = vars->nodes[i];
3581
3582 vars->nodes[i] = NULL;
3583 dropNode(node);
3584 }
3585
3586 xmlFuzzMemSetLimit(0);
3587 xmlFuzzDataCleanup();
3588 xmlResetLastError();
3589 return(0);
3590 }
3591
3592