diff options
author | Nick Wellnhofer <wellnhofer@aevum.de> | 2019-10-04 14:42:59 +0200 |
---|---|---|
committer | Nick Wellnhofer <wellnhofer@aevum.de> | 2019-10-04 14:42:59 +0200 |
commit | 24e3973bc03c15d534b2eac6e70fc2b2bef2b6c0 (patch) | |
tree | eef46e5233ed46c68e3107226aba59805268a581 | |
parent | 64966ebefdbd350a2c34577f1bf88e39b3a48ece (diff) | |
download | libxml2-24e3973bc03c15d534b2eac6e70fc2b2bef2b6c0.tar.gz |
Make xmlDumpElementContent non-recursive
Avoid call stack overflow when dumping deeply nested element
declarations.
Found by OSS-Fuzz.
-rw-r--r-- | valid.c | 157 |
1 files changed, 89 insertions, 68 deletions
@@ -1148,84 +1148,105 @@ xmlFreeElementContent(xmlElementContentPtr cur) { #ifdef LIBXML_OUTPUT_ENABLED /** - * xmlDumpElementContent: + * xmlDumpElementOccur: * @buf: An XML buffer - * @content: An element table - * @glob: 1 if one must print the englobing parenthesis, 0 otherwise + * @cur: An element table * - * This will dump the content of the element table as an XML DTD definition + * Dump the occurence operator of an element. */ static void -xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) { - if (content == NULL) return; - - if (glob) xmlBufferWriteChar(buf, "("); - switch (content->type) { - case XML_ELEMENT_CONTENT_PCDATA: - xmlBufferWriteChar(buf, "#PCDATA"); - break; - case XML_ELEMENT_CONTENT_ELEMENT: - if (content->prefix != NULL) { - xmlBufferWriteCHAR(buf, content->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, content->name); - break; - case XML_ELEMENT_CONTENT_SEQ: - if ((content->c1 != NULL) && - ((content->c1->type == XML_ELEMENT_CONTENT_OR) || - (content->c1->type == XML_ELEMENT_CONTENT_SEQ))) - xmlDumpElementContent(buf, content->c1, 1); - else - xmlDumpElementContent(buf, content->c1, 0); - xmlBufferWriteChar(buf, " , "); - if ((content->c2 != NULL) && - ((content->c2->type == XML_ELEMENT_CONTENT_OR) || - ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) && - (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))) - xmlDumpElementContent(buf, content->c2, 1); - else - xmlDumpElementContent(buf, content->c2, 0); - break; - case XML_ELEMENT_CONTENT_OR: - if ((content->c1 != NULL) && - ((content->c1->type == XML_ELEMENT_CONTENT_OR) || - (content->c1->type == XML_ELEMENT_CONTENT_SEQ))) - xmlDumpElementContent(buf, content->c1, 1); - else - xmlDumpElementContent(buf, content->c1, 0); - xmlBufferWriteChar(buf, " | "); - if ((content->c2 != NULL) && - ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || - ((content->c2->type == XML_ELEMENT_CONTENT_OR) && - (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))) - xmlDumpElementContent(buf, content->c2, 1); - else - xmlDumpElementContent(buf, content->c2, 0); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT content corrupted invalid type\n", - NULL); - } - if (glob) - xmlBufferWriteChar(buf, ")"); - switch (content->ocur) { +xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) { + switch (cur->ocur) { case XML_ELEMENT_CONTENT_ONCE: - break; + break; case XML_ELEMENT_CONTENT_OPT: - xmlBufferWriteChar(buf, "?"); - break; + xmlBufferWriteChar(buf, "?"); + break; case XML_ELEMENT_CONTENT_MULT: - xmlBufferWriteChar(buf, "*"); - break; + xmlBufferWriteChar(buf, "*"); + break; case XML_ELEMENT_CONTENT_PLUS: - xmlBufferWriteChar(buf, "+"); - break; + xmlBufferWriteChar(buf, "+"); + break; } } /** + * xmlDumpElementContent: + * @buf: An XML buffer + * @content: An element table + * + * This will dump the content of the element table as an XML DTD definition + */ +static void +xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) { + xmlElementContentPtr cur; + + if (content == NULL) return; + + xmlBufferWriteChar(buf, "("); + cur = content; + + do { + if (cur == NULL) return; + + switch (cur->type) { + case XML_ELEMENT_CONTENT_PCDATA: + xmlBufferWriteChar(buf, "#PCDATA"); + break; + case XML_ELEMENT_CONTENT_ELEMENT: + if (cur->prefix != NULL) { + xmlBufferWriteCHAR(buf, cur->prefix); + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, cur->name); + break; + case XML_ELEMENT_CONTENT_SEQ: + case XML_ELEMENT_CONTENT_OR: + if ((cur != content) && + (cur->parent != NULL) && + ((cur->type != cur->parent->type) || + (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlBufferWriteChar(buf, "("); + cur = cur->c1; + continue; + default: + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "Internal: ELEMENT cur corrupted invalid type\n", + NULL); + } + + while (cur != content) { + xmlElementContentPtr parent = cur->parent; + + if (parent == NULL) return; + + if (((cur->type == XML_ELEMENT_CONTENT_OR) || + (cur->type == XML_ELEMENT_CONTENT_SEQ)) && + ((cur->type != parent->type) || + (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlBufferWriteChar(buf, ")"); + xmlDumpElementOccur(buf, cur); + + if (cur == parent->c1) { + if (parent->type == XML_ELEMENT_CONTENT_SEQ) + xmlBufferWriteChar(buf, " , "); + else if (parent->type == XML_ELEMENT_CONTENT_OR) + xmlBufferWriteChar(buf, " | "); + + cur = parent->c2; + break; + } + + cur = parent; + } + } while (cur != content); + + xmlBufferWriteChar(buf, ")"); + xmlDumpElementOccur(buf, content); +} + +/** * xmlSprintfElementContent: * @buf: an output buffer * @content: An element table @@ -1703,7 +1724,7 @@ xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { } xmlBufferWriteCHAR(buf, elem->name); xmlBufferWriteChar(buf, " "); - xmlDumpElementContent(buf, elem->content, 1); + xmlDumpElementContent(buf, elem->content); xmlBufferWriteChar(buf, ">\n"); break; case XML_ELEMENT_TYPE_ELEMENT: @@ -1714,7 +1735,7 @@ xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { } xmlBufferWriteCHAR(buf, elem->name); xmlBufferWriteChar(buf, " "); - xmlDumpElementContent(buf, elem->content, 1); + xmlDumpElementContent(buf, elem->content); xmlBufferWriteChar(buf, ">\n"); break; default: |