@@ -1391,13 +1391,14 @@ xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
13911391static void
13921392xhtmlNodeDumpOutput (xmlSaveCtxtPtr ctxt , xmlNodePtr cur ) {
13931393 int format = ctxt -> format , addmeta ;
1394- xmlNodePtr tmp , root , unformattedNode = NULL ;
1394+ xmlNodePtr tmp , root , unformattedNode = NULL , parent ;
13951395 xmlChar * start , * end ;
13961396 xmlOutputBufferPtr buf = ctxt -> buf ;
13971397
13981398 if (cur == NULL ) return ;
13991399
14001400 root = cur ;
1401+ parent = cur -> parent ;
14011402 while (1 ) {
14021403 switch (cur -> type ) {
14031404 case XML_DOCUMENT_NODE :
@@ -1414,7 +1415,9 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
14141415 break ;
14151416
14161417 case XML_DOCUMENT_FRAG_NODE :
1417- if (cur -> children ) {
1418+ /* Always validate cur->parent when descending. */
1419+ if ((cur -> parent == parent ) && (cur -> children != NULL )) {
1420+ parent = cur ;
14181421 cur = cur -> children ;
14191422 continue ;
14201423 }
@@ -1441,6 +1444,16 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
14411444 ctxt -> indent_nr : ctxt -> level ),
14421445 ctxt -> indent );
14431446
1447+ /*
1448+ * Some users like lxml are known to pass nodes with a corrupted
1449+ * tree structure. Fall back to a recursive call to handle this
1450+ * case.
1451+ */
1452+ if ((cur -> parent != parent ) && (cur -> children != NULL )) {
1453+ xhtmlNodeDumpOutput (ctxt , cur );
1454+ break ;
1455+ }
1456+
14441457 xmlOutputBufferWrite (buf , 1 , "<" );
14451458 if ((cur -> ns != NULL ) && (cur -> ns -> prefix != NULL )) {
14461459 xmlOutputBufferWriteString (buf , (const char * )cur -> ns -> prefix );
@@ -1461,10 +1474,10 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
14611474 if (cur -> properties != NULL )
14621475 xhtmlAttrListDumpOutput (ctxt , cur -> properties );
14631476
1464- if ((cur -> parent != NULL ) &&
1465- (cur -> parent -> parent == (xmlNodePtr ) cur -> doc ) &&
1477+ if ((parent != NULL ) &&
1478+ (parent -> parent == (xmlNodePtr ) cur -> doc ) &&
14661479 xmlStrEqual (cur -> name , BAD_CAST "head" ) &&
1467- xmlStrEqual (cur -> parent -> name , BAD_CAST "html" )) {
1480+ xmlStrEqual (parent -> name , BAD_CAST "html" )) {
14681481
14691482 tmp = cur -> children ;
14701483 while (tmp != NULL ) {
@@ -1570,6 +1583,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
15701583
15711584 if (ctxt -> format == 1 ) xmlOutputBufferWrite (buf , 1 , "\n" );
15721585 if (ctxt -> level >= 0 ) ctxt -> level ++ ;
1586+ parent = cur ;
15731587 cur = cur -> children ;
15741588 continue ;
15751589 }
@@ -1664,13 +1678,9 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
16641678 break ;
16651679 }
16661680
1667- /*
1668- * The parent should never be NULL here but we want to handle
1669- * corrupted documents gracefully.
1670- */
1671- if (cur -> parent == NULL )
1672- return ;
1673- cur = cur -> parent ;
1681+ cur = parent ;
1682+ /* cur->parent was validated when descending. */
1683+ parent = cur -> parent ;
16741684
16751685 if (cur -> type == XML_ELEMENT_NODE ) {
16761686 if (ctxt -> level > 0 ) ctxt -> level -- ;
0 commit comments