]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
xml2: Fix crash with namespace nodes in xpath_nodeset()
authorMichael Paquier <michael@paquier.xyz>
Thu, 11 Jun 2026 05:29:18 +0000 (14:29 +0900)
committerMichael Paquier <michael@paquier.xyz>
Thu, 11 Jun 2026 05:29:18 +0000 (14:29 +0900)
pgxmlNodeSetToText() passed nodeTab[i]->doc to xmlNodeDump() without
checking the node type, which could cause a crash as a
XML_NAMESPACE_DECL maps to a xmlNs struct.  The passed-in code would
then be dereferenced in xmlNodeDump().

This commit switches the code to render XML_NAMESPACE_DECL nodes with
xmlXPathCastNodeToString(), like xpath_table().  Some tests are added,
written by me.

Author: Andrey Chernyy <andrey.cherny@tantorlabs.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/20260611031436.5afde3cb@andrnote
Backpatch-through: 14

contrib/xml2/expected/xml2.out
contrib/xml2/expected/xml2_1.out
contrib/xml2/sql/xml2.sql
contrib/xml2/xpath.c

index 1906fcf33e2a5c0e9a6a1435aaf30c2464834dd2..9078f15f6b3598f8352a89e3b9b2cfdbc17c2916 100644 (file)
@@ -231,6 +231,14 @@ SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages',
  <result><item><author>test</author></item><item><pages>37</pages></item></result>
 (1 row)
 
+-- namespace node
+SELECT xpath_nodeset('<root xmlns:foo="http://icl.com/saxon"/>',
+                     '//namespace::foo');
+    xpath_nodeset     
+----------------------
+ http://icl.com/saxon
+(1 row)
+
 -- xpath_list()
 SELECT xpath_list(article_xml::text, '/article/author|/article/pages')
   FROM articles;
index 9a2144d58f577b902b7b74c4d311efe4171dda40..62e8bd6802ad01df4c3adeaf063d630755c630bc 100644 (file)
@@ -175,6 +175,14 @@ SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages',
  <result><item><author>test</author></item><item><pages>37</pages></item></result>
 (1 row)
 
+-- namespace node
+SELECT xpath_nodeset('<root xmlns:foo="http://icl.com/saxon"/>',
+                     '//namespace::foo');
+    xpath_nodeset     
+----------------------
+ http://icl.com/saxon
+(1 row)
+
 -- xpath_list()
 SELECT xpath_list(article_xml::text, '/article/author|/article/pages')
   FROM articles;
index 510d18a367996b8b56e7b943f7c424a62f1569f8..145c487cbdea29090f25e1ac67d651a00957c774 100644 (file)
@@ -132,6 +132,9 @@ SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages',
 SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages',
                      'result', 'item')
   FROM articles;
+-- namespace node
+SELECT xpath_nodeset('<root xmlns:foo="http://icl.com/saxon"/>',
+                     '//namespace::foo');
 
 -- xpath_list()
 SELECT xpath_list(article_xml::text, '/article/author|/article/pages')
index 283bb51178d12970ffdfa28425c715c21ad7bb28..391e39827ce226c72c42f67f0df997c719fdadd9 100644 (file)
@@ -188,16 +188,31 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
                                }
                                else
                                {
+                                       xmlNodePtr      node = nodeset->nodeTab[i];
+
                                        if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
                                        {
                                                xmlBufferWriteChar(buf, "<");
                                                xmlBufferWriteCHAR(buf, septagname);
                                                xmlBufferWriteChar(buf, ">");
                                        }
-                                       xmlNodeDump(buf,
-                                                               nodeset->nodeTab[i]->doc,
-                                                               nodeset->nodeTab[i],
-                                                               1, 0);
+
+                                       /*
+                                        * XML_NAMESPACE_DECL nodes are xmlNs structs, that cannot
+                                        * be processed by xmlNodeDump().
+                                        */
+                                       if (node->type == XML_NAMESPACE_DECL)
+                                       {
+                                               str = xmlXPathCastNodeToString(node);
+                                               if (str == NULL || pg_xml_error_occurred(xmlerrcxt))
+                                                       xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
+                                                                               "could not allocate node text");
+                                               xmlBufferWriteCHAR(buf, str);
+                                               xmlFree(str);
+                                               str = NULL;
+                                       }
+                                       else
+                                               xmlNodeDump(buf, node->doc, node, 1, 0);
 
                                        if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
                                        {