Fix #70078: XSL callbacks with nodes as parameter leak memory

The fix for bug #49634 solved a double-free by copying the node with
`xmlDocCopyNodeList()`, but the copied node is later freed by calling
`xmlFreeNode()` instead of `xmlFreeNodeList()`, thus leaking memory.
However, there is no need to treat the node as node list, i.e. to copy
also the node's siblings; just creating a recursive copy of the node
with `xmlDocCopyNode()` is sufficient, while that also avoids the leak.
This commit is contained in:
Christoph M. Becker 2020-01-29 18:23:51 +01:00
parent 494615fcb8
commit 8226e704e4
3 changed files with 55 additions and 1 deletions

3
NEWS
View file

@ -36,6 +36,9 @@ PHP NEWS
- Standard:
. Fixed bug #78902 (Memory leak when using stream_filter_append). (liudaixiao)
- XSL:
. Fixed bug #70078 (XSL callbacks with nodes as parameter leak memory). (cmb)
23 Jan 2020, PHP 7.3.14
- Core

View file

@ -0,0 +1,51 @@
--TEST--
Bug #70078 (XSL callbacks with nodes as parameter leak memory)
--SKIPIF--
<?php
if (!extension_loaded('xsl')) die('skip xsl extension not available');
?>
--FILE--
<?php
// create big dummy document:
$dom = new \DOMDocument();
$rootNode = $dom->appendChild($dom->createElement('root'));
for ($i = 0; $i <= 100; $i++) {
$level1Node = $rootNode->appendChild($dom->createElement('level1'));
for ($j = 0; $j <= 100; $j++) {
$level2Node = $level1Node->appendChild($dom->createElement('level2'));
for ($k = 0; $k <= 10; $k++) {
$level3Node = $level2Node->appendChild($dom->createElement('level3', 'test'));
}
}
}
function testPhpFunction($node) {
return 'test2';
}
$xslStr = <<<EOF
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
<xsl:template match="root">
<output>
<xsl:for-each select="level1">
<node>
<xsl:value-of select="php:function('testPhpFunction', .)" />
</node>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
EOF;
$xsl = new \DOMDocument();
$xsl->loadXML($xslStr);
$xslt = new \XSLTProcessor();
$xslt->registerPHPFunctions('testPhpFunction');
$xslt->importStyleSheet($xsl);
echo $xslt->transformToXML($dom);
?>
--EXPECT--
<?xml version="1.0"?>
<output xmlns:php="http://php.net/xsl"><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node><node>test2</node></output>

View file

@ -274,7 +274,7 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t
node->parent = nsparent;
node->ns = curns;
} else {
node = xmlDocCopyNodeList(domintern->document->ptr, node);
node = xmlDocCopyNode(node, domintern->document->ptr, 1);
}
php_dom_create_object(node, &child, domintern);