postgresql/contrib/xml2/expected/xml2.out
Michael Paquier 7d64419f80 xml2: Fix failure with xslt_process() under -fsanitize=undefined
The logic of xslt_process() has never considered the fact that
xsltSaveResultToString() would return NULL for an empty string (the
upstream code has always done so, with a string length of 0).  This
would cause memcpy() to be called with a NULL pointer, something
forbidden by POSIX.

Like 46ab07ffda and similar fixes, this is backpatched down to all the
supported branches, with a test case to cover this scenario.  An empty
string has been always returned in xml2 in this case, based on the
history of the module, so this is an old issue.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/c516a0d9-4406-47e3-9087-5ca5176ebcf9@gmail.com
Backpatch-through: 14
2026-03-13 16:06:28 +09:00

273 lines
9.3 KiB
Text

CREATE EXTENSION xml2;
select query_to_xml('select 1 as x',true,false,'');
query_to_xml
---------------------------------------------------------------
<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">+
+
<row> +
<x>1</x> +
</row> +
+
</table> +
(1 row)
select xslt_process( query_to_xml('select x from generate_series(1,5) as
x',true,false,'')::text,
$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="comment()|processing-instruction()">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
$$::text);
xslt_process
---------------------------------------------------------------
<?xml version="1.0"?> +
<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">+
+
<row> +
<x>1</x> +
</row> +
+
<row> +
<x>2</x> +
</row> +
+
<row> +
<x>3</x> +
</row> +
+
<row> +
<x>4</x> +
</row> +
+
<row> +
<x>5</x> +
</row> +
+
</table> +
(1 row)
CREATE TABLE xpath_test (id integer NOT NULL, t xml);
INSERT INTO xpath_test VALUES (1, '<doc><int>1</int></doc>');
SELECT * FROM xpath_table('id', 't', 'xpath_test', '/doc/int', 'true')
as t(id int4);
id
----
(0 rows)
SELECT * FROM xpath_table('id', 't', 'xpath_test', '/doc/int', 'true')
as t(id int4, doc int4);
id | doc
----+-----
1 | 1
(1 row)
DROP TABLE xpath_test;
CREATE TABLE xpath_test (id integer NOT NULL, t text);
INSERT INTO xpath_test VALUES (1, '<doc><int>1</int></doc>');
SELECT * FROM xpath_table('id', 't', 'xpath_test', '/doc/int', 'true')
as t(id int4);
id
----
(0 rows)
SELECT * FROM xpath_table('id', 't', 'xpath_test', '/doc/int', 'true')
as t(id int4, doc int4);
id | doc
----+-----
1 | 1
(1 row)
create table articles (article_id integer, article_xml xml, date_entered date);
insert into articles (article_id, article_xml, date_entered)
values (2, '<article><author>test</author><pages>37</pages></article>', now());
SELECT * FROM
xpath_table('article_id',
'article_xml',
'articles',
'/article/author|/article/pages|/article/title',
'date_entered > ''2003-01-01'' ')
AS t(article_id integer, author text, page_count integer, title text);
article_id | author | page_count | title
------------+--------+------------+-------
2 | test | 37 |
(1 row)
-- this used to fail when invoked a second time
select xslt_process('<aaa/>',$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>$$)::xml;
xslt_process
--------------
<aaa/> +
(1 row)
select xslt_process('<aaa/>',$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>$$)::xml;
xslt_process
--------------
<aaa/> +
(1 row)
create table t1 (id integer, xml_data xml);
insert into t1 (id, xml_data)
values
(1, '<attributes><attribute name="attr_1">Some
Value</attribute></attributes>');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></employee>'::text, $$<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="n1"/>
<xsl:param name="n2"/>
<xsl:param name="n3"/>
<xsl:param name="n4"/>
<xsl:param name="n5" select="'me'"/>
<xsl:template match="*">
<xsl:element name="samples">
<xsl:element name="sample">
<xsl:value-of select="$n1"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n2"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n3"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n4"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n5"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n6"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n7"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n8"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n9"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n10"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n11"/>
</xsl:element>
<xsl:element name="sample">
<xsl:value-of select="$n12"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
xslt_process
------------------------
<samples> +
<sample>v1</sample> +
<sample>v2</sample> +
<sample>v3</sample> +
<sample>v4</sample> +
<sample>v5</sample> +
<sample>v6</sample> +
<sample>v7</sample> +
<sample>v8</sample> +
<sample>v9</sample> +
<sample>v10</sample>+
<sample>v11</sample>+
<sample>v12</sample>+
</samples> +
(1 row)
-- xpath_nodeset()
SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages')
FROM articles;
xpath_nodeset
----------------------------------------
<author>test</author><pages>37</pages>
(1 row)
SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages',
'item_without_toptag')
FROM articles;
xpath_nodeset
------------------------------------------------------------------------------------------------------------------------------
<item_without_toptag><author>test</author></item_without_toptag><item_without_toptag><pages>37</pages></item_without_toptag>
(1 row)
SELECT xpath_nodeset(article_xml::text, '/article/author|/article/pages',
'result', 'item')
FROM articles;
xpath_nodeset
-----------------------------------------------------------------------------------
<result><item><author>test</author></item><item><pages>37</pages></item></result>
(1 row)
-- xpath_list()
SELECT xpath_list(article_xml::text, '/article/author|/article/pages')
FROM articles;
xpath_list
------------
test,37
(1 row)
SELECT xpath_list(article_xml::text, '/article/author|/article/pages', '|')
FROM articles;
xpath_list
------------
test|37
(1 row)
-- possible security exploit
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sax="http://icl.com/saxon"
extension-element-prefixes="sax">
<xsl:template match="//foo">
<sax:output href="0wn3d.txt" method="text">
<xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
<xsl:apply-templates/>
</sax:output>
</xsl:template>
</xsl:stylesheet>$$);
ERROR: failed to apply stylesheet
-- empty output
select xslt_process('<aaa/>',
$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>$$);
xslt_process
--------------
(1 row)