libxml2/Make-xmlNodeDumpOutputInternal-non-recursive.patch

551 lines
18 KiB
Diff
Raw Normal View History

2021-10-21 17:46:40 +08:00
From dc6f009280e6108fe25f4c4ce32e18fb69cf496e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 28 Jul 2020 19:07:19 +0200
Subject: [PATCH] Make xmlNodeDumpOutputInternal non-recursive
Fixes stack overflow with deeply nested documents.
---
xmlsave.c | 470 ++++++++++++++++++++++++++++++++------------------------------
1 file changed, 240 insertions(+), 230 deletions(-)
diff --git a/xmlsave.c b/xmlsave.c
index cf32d69..2235c8f 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -590,7 +590,6 @@ static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
static void
xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
#endif
-static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
@@ -705,6 +704,7 @@ xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
static void
xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
xmlOutputBufferPtr buf;
+ xmlNodePtr cur;
int format, level;
if (dtd == NULL) return;
@@ -742,7 +742,9 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
level = ctxt->level;
ctxt->format = 0;
ctxt->level = -1;
- xmlNodeListDumpOutput(ctxt, dtd->children);
+ for (cur = dtd->children; cur != NULL; cur = cur->next) {
+ xmlNodeDumpOutputInternal(ctxt, cur);
+ }
ctxt->format = format;
ctxt->level = level;
xmlOutputBufferWrite(buf, 2, "]>");
@@ -776,58 +778,9 @@ xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
xmlOutputBufferWrite(buf, 1, "\"");
}
-/**
- * xmlAttrListDumpOutput:
- * @buf: the XML buffer output
- * @doc: the document
- * @cur: the first attribute pointer
- * @encoding: an optional encoding string
- *
- * Dump a list of XML attributes
- */
-static void
-xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
- if (cur == NULL) return;
- while (cur != NULL) {
- xmlAttrDumpOutput(ctxt, cur);
- cur = cur->next;
- }
-}
-
-
-
-/**
- * xmlNodeListDumpOutput:
- * @cur: the first node
- *
- * Dump an XML node list, recursive behaviour, children are printed too.
- */
-static void
-xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
- xmlOutputBufferPtr buf;
-
- if (cur == NULL) return;
- buf = ctxt->buf;
- while (cur != NULL) {
- if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
- ((cur->type == XML_ELEMENT_NODE) ||
- (cur->type == XML_COMMENT_NODE) ||
- (cur->type == XML_PI_NODE)))
- xmlOutputBufferWrite(buf, ctxt->indent_size *
- (ctxt->level > ctxt->indent_nr ?
- ctxt->indent_nr : ctxt->level),
- ctxt->indent);
- xmlNodeDumpOutputInternal(ctxt, cur);
- if (ctxt->format == 1) {
- xmlOutputBufferWrite(buf, 1, "\n");
- }
- cur = cur->next;
- }
-}
-
#ifdef LIBXML_HTML_ENABLED
/**
- * xmlNodeDumpOutputInternal:
+ * htmlNodeDumpOutputInternal:
* @cur: the current node
*
* Dump an HTML node, recursive behaviour, children are printed too.
@@ -893,57 +846,111 @@ htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
*/
static void
xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
- int format;
- xmlNodePtr tmp;
+ int format = ctxt->format;
+ xmlNodePtr tmp, root, unformattedNode = NULL;
+ xmlAttrPtr attr;
xmlChar *start, *end;
xmlOutputBufferPtr buf;
if (cur == NULL) return;
buf = ctxt->buf;
- if (cur->type == XML_XINCLUDE_START)
- return;
- if (cur->type == XML_XINCLUDE_END)
- return;
- if ((cur->type == XML_DOCUMENT_NODE) ||
- (cur->type == XML_HTML_DOCUMENT_NODE)) {
- xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
- return;
- }
-#ifdef LIBXML_HTML_ENABLED
- if (ctxt->options & XML_SAVE_XHTML) {
- xhtmlNodeDumpOutput(ctxt, cur);
- return;
- }
- if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
- (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
- ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
- (ctxt->options & XML_SAVE_AS_HTML)) {
- htmlNodeDumpOutputInternal(ctxt, cur);
- return;
- }
-#endif
- if (cur->type == XML_DTD_NODE) {
- xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
- return;
- }
- if (cur->type == XML_DOCUMENT_FRAG_NODE) {
- xmlNodeListDumpOutput(ctxt, cur->children);
- return;
- }
- if (cur->type == XML_ELEMENT_DECL) {
- xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
- return;
- }
- if (cur->type == XML_ATTRIBUTE_DECL) {
- xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
- return;
- }
- if (cur->type == XML_ENTITY_DECL) {
- xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
- return;
- }
- if (cur->type == XML_TEXT_NODE) {
- if (cur->content != NULL) {
+
+ root = cur;
+ while (1) {
+ switch (cur->type) {
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
+ break;
+
+ case XML_DTD_NODE:
+ xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
+ break;
+
+ case XML_DOCUMENT_FRAG_NODE:
+ if (cur->children != NULL) {
+ cur = cur->children;
+ continue;
+ }
+ break;
+
+ case XML_ELEMENT_DECL:
+ xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
+ break;
+
+ case XML_ATTRIBUTE_DECL:
+ xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
+ break;
+
+ case XML_ENTITY_DECL:
+ xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
+ break;
+
+ case XML_ELEMENT_NODE:
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
+
+ xmlOutputBufferWrite(buf, 1, "<");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+ xmlOutputBufferWrite(buf, 1, ":");
+ }
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (cur->nsDef)
+ xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
+ for (attr = cur->properties; attr != NULL; attr = attr->next)
+ xmlAttrDumpOutput(ctxt, attr);
+
+ if (cur->children == NULL) {
+ if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 2, "/>");
+ } else {
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 1);
+ xmlOutputBufferWrite(buf, 3, "></");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf,
+ (const char *)cur->ns->prefix);
+ xmlOutputBufferWrite(buf, 1, ":");
+ }
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 1, ">");
+ }
+ } else {
+ if (ctxt->format == 1) {
+ tmp = cur->children;
+ while (tmp != NULL) {
+ if ((tmp->type == XML_TEXT_NODE) ||
+ (tmp->type == XML_CDATA_SECTION_NODE) ||
+ (tmp->type == XML_ENTITY_REF_NODE)) {
+ ctxt->format = 0;
+ unformattedNode = cur;
+ break;
+ }
+ tmp = tmp->next;
+ }
+ }
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 1);
+ xmlOutputBufferWrite(buf, 1, ">");
+ if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
+ if (ctxt->level >= 0) ctxt->level++;
+ cur = cur->children;
+ continue;
+ }
+
+ break;
+
+ case XML_TEXT_NODE:
+ if (cur->content == NULL)
+ break;
if (cur->name != xmlStringTextNoenc) {
xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
} else {
@@ -952,139 +959,129 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
*/
xmlOutputBufferWriteString(buf, (const char *) cur->content);
}
- }
+ break;
- return;
- }
- if (cur->type == XML_PI_NODE) {
- if (cur->content != NULL) {
- xmlOutputBufferWrite(buf, 2, "<?");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (cur->content != NULL) {
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- else
- xmlOutputBufferWrite(buf, 1, " ");
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- }
- xmlOutputBufferWrite(buf, 2, "?>");
- } else {
- xmlOutputBufferWrite(buf, 2, "<?");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- xmlOutputBufferWrite(buf, 2, "?>");
- }
- return;
- }
- if (cur->type == XML_COMMENT_NODE) {
- if (cur->content != NULL) {
- xmlOutputBufferWrite(buf, 4, "<!--");
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- xmlOutputBufferWrite(buf, 3, "-->");
- }
- return;
- }
- if (cur->type == XML_ENTITY_REF_NODE) {
- xmlOutputBufferWrite(buf, 1, "&");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- xmlOutputBufferWrite(buf, 1, ";");
- return;
- }
- if (cur->type == XML_CDATA_SECTION_NODE) {
- if (cur->content == NULL || *cur->content == '\0') {
- xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
- } else {
- start = end = cur->content;
- while (*end != '\0') {
- if ((*end == ']') && (*(end + 1) == ']') &&
- (*(end + 2) == '>')) {
- end = end + 2;
- xmlOutputBufferWrite(buf, 9, "<![CDATA[");
- xmlOutputBufferWrite(buf, end - start, (const char *)start);
- xmlOutputBufferWrite(buf, 3, "]]>");
- start = end;
- }
- end++;
- }
- if (start != end) {
- xmlOutputBufferWrite(buf, 9, "<![CDATA[");
- xmlOutputBufferWriteString(buf, (const char *)start);
- xmlOutputBufferWrite(buf, 3, "]]>");
- }
- }
- return;
- }
- if (cur->type == XML_ATTRIBUTE_NODE) {
- xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
- return;
- }
- if (cur->type == XML_NAMESPACE_DECL) {
- xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
- return;
- }
+ case XML_PI_NODE:
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
- format = ctxt->format;
- if (format == 1) {
- tmp = cur->children;
- while (tmp != NULL) {
- if ((tmp->type == XML_TEXT_NODE) ||
- (tmp->type == XML_CDATA_SECTION_NODE) ||
- (tmp->type == XML_ENTITY_REF_NODE)) {
- ctxt->format = 0;
- break;
- }
- tmp = tmp->next;
- }
- }
- xmlOutputBufferWrite(buf, 1, "<");
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
- xmlOutputBufferWrite(buf, 1, ":");
- }
+ if (cur->content != NULL) {
+ xmlOutputBufferWrite(buf, 2, "<?");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (cur->content != NULL) {
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ else
+ xmlOutputBufferWrite(buf, 1, " ");
+ xmlOutputBufferWriteString(buf,
+ (const char *)cur->content);
+ }
+ xmlOutputBufferWrite(buf, 2, "?>");
+ } else {
+ xmlOutputBufferWrite(buf, 2, "<?");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 2, "?>");
+ }
+ break;
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (cur->nsDef)
- xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
- if (cur->properties != NULL)
- xmlAttrListDumpOutput(ctxt, cur->properties);
-
- if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
- (cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) {
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- xmlOutputBufferWrite(buf, 2, "/>");
- ctxt->format = format;
- return;
- }
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 1);
- xmlOutputBufferWrite(buf, 1, ">");
- if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
- xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
- }
- if (cur->children != NULL) {
- if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
- if (ctxt->level >= 0) ctxt->level++;
- xmlNodeListDumpOutput(ctxt, cur->children);
- if (ctxt->level > 0) ctxt->level--;
- if ((xmlIndentTreeOutput) && (ctxt->format == 1))
- xmlOutputBufferWrite(buf, ctxt->indent_size *
- (ctxt->level > ctxt->indent_nr ?
- ctxt->indent_nr : ctxt->level),
- ctxt->indent);
- }
- xmlOutputBufferWrite(buf, 2, "</");
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
- xmlOutputBufferWrite(buf, 1, ":");
- }
+ case XML_COMMENT_NODE:
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- xmlOutputBufferWrite(buf, 1, ">");
- ctxt->format = format;
+ if (cur->content != NULL) {
+ xmlOutputBufferWrite(buf, 4, "<!--");
+ xmlOutputBufferWriteString(buf, (const char *)cur->content);
+ xmlOutputBufferWrite(buf, 3, "-->");
+ }
+ break;
+
+ case XML_ENTITY_REF_NODE:
+ xmlOutputBufferWrite(buf, 1, "&");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ xmlOutputBufferWrite(buf, 1, ";");
+ break;
+
+ case XML_CDATA_SECTION_NODE:
+ if (cur->content == NULL || *cur->content == '\0') {
+ xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
+ } else {
+ start = end = cur->content;
+ while (*end != '\0') {
+ if ((*end == ']') && (*(end + 1) == ']') &&
+ (*(end + 2) == '>')) {
+ end = end + 2;
+ xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+ xmlOutputBufferWrite(buf, end - start,
+ (const char *)start);
+ xmlOutputBufferWrite(buf, 3, "]]>");
+ start = end;
+ }
+ end++;
+ }
+ if (start != end) {
+ xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+ xmlOutputBufferWriteString(buf, (const char *)start);
+ xmlOutputBufferWrite(buf, 3, "]]>");
+ }
+ }
+ break;
+
+ case XML_ATTRIBUTE_NODE:
+ xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
+ break;
+
+ case XML_NAMESPACE_DECL:
+ xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
+ break;
+
+ default:
+ break;
+ }
+
+ while (1) {
+ if (cur == root)
+ return;
+ if (ctxt->format == 1) {
+ xmlOutputBufferWrite(buf, 1, "\n");
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+
+ cur = cur->parent;
+
+ if (ctxt->level > 0) ctxt->level--;
+ if ((xmlIndentTreeOutput) && (ctxt->format == 1))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
+ if (cur == unformattedNode) {
+ ctxt->format = format;
+ unformattedNode = NULL;
+ }
+
+ xmlOutputBufferWrite(buf, 2, "</");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+ xmlOutputBufferWrite(buf, 1, ":");
+ }
+
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 1, ">");
+ }
+ }
}
/**
@@ -1865,12 +1862,25 @@ xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
* Returns the number of byte written or -1 in case of error
*/
long
-xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node)
+xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
{
long ret = 0;
- if ((ctxt == NULL) || (node == NULL)) return(-1);
- xmlNodeDumpOutputInternal(ctxt, node);
+ if ((ctxt == NULL) || (cur == NULL)) return(-1);
+#ifdef LIBXML_HTML_ENABLED
+ if (ctxt->options & XML_SAVE_XHTML) {
+ xhtmlNodeDumpOutput(ctxt, cur);
+ return(ret);
+ }
+ if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
+ (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
+ ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
+ (ctxt->options & XML_SAVE_AS_HTML)) {
+ htmlNodeDumpOutputInternal(ctxt, cur);
+ return(ret);
+ }
+#endif
+ xmlNodeDumpOutputInternal(ctxt, cur);
return(ret);
}
--
1.8.3.1