|
| 1 | +--TEST-- |
| 2 | +GH-23730 (Use-after-free when a stylesheet is imported during a transformation) |
| 3 | +--EXTENSIONS-- |
| 4 | +dom |
| 5 | +xsl |
| 6 | +--CREDITS-- |
| 7 | +djarfluka |
| 8 | +--FILE-- |
| 9 | +<?php |
| 10 | + |
| 11 | +class MyElement extends DOMElement { |
| 12 | + public function __destruct() { |
| 13 | + /* Runs while the node list of the finished transformation is torn down. */ |
| 14 | + import_other('destructor'); |
| 15 | + } |
| 16 | +} |
| 17 | + |
| 18 | +function import_other(string $from) { |
| 19 | + try { |
| 20 | + $GLOBALS['proc']->importStylesheet($GLOBALS['other']); |
| 21 | + echo $from, ': no error', PHP_EOL; |
| 22 | + } catch (Error $e) { |
| 23 | + echo $from, ': ', $e::class, ': ', $e->getMessage(), PHP_EOL; |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +function callback($nodes) { |
| 28 | + import_other('callback'); |
| 29 | + return $nodes[0]; |
| 30 | +} |
| 31 | + |
| 32 | +$xml = new DOMDocument(); |
| 33 | +$xml->registerNodeClass(DOMElement::class, MyElement::class); |
| 34 | +$xml->loadXML('<root><item>a</item></root>'); |
| 35 | + |
| 36 | +$xsl = new DOMDocument(); |
| 37 | +$xsl->loadXML(<<<XML |
| 38 | +<?xml version="1.0"?> |
| 39 | +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl"> |
| 40 | + <xsl:template match="/"><xsl:value-of select="php:function('callback', //item)"/></xsl:template> |
| 41 | +</xsl:stylesheet> |
| 42 | +XML); |
| 43 | + |
| 44 | +$other = new DOMDocument(); |
| 45 | +$other->loadXML('<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/">REPLACED</xsl:template></xsl:stylesheet>'); |
| 46 | + |
| 47 | +$proc = new XSLTProcessor(); |
| 48 | +$proc->registerPHPFunctions(); |
| 49 | +$proc->importStylesheet($xsl); |
| 50 | + |
| 51 | +$GLOBALS['proc'] = $proc; |
| 52 | +$GLOBALS['other'] = $other; |
| 53 | + |
| 54 | +var_dump($proc->transformToXml($xml)); |
| 55 | +var_dump($proc->transformToDoc($xml)->textContent); |
| 56 | + |
| 57 | +$uri = tempnam(sys_get_temp_dir(), 'gh23730'); |
| 58 | +var_dump($proc->transformToUri($xml, $uri) > 0); |
| 59 | +@unlink($uri); |
| 60 | + |
| 61 | +/* Importing outside of a transformation is still allowed. */ |
| 62 | +var_dump($proc->importStylesheet($other)); |
| 63 | +var_dump($proc->transformToXml($xml)); |
| 64 | + |
| 65 | +?> |
| 66 | +--EXPECT-- |
| 67 | +callback: Error: Cannot call XSLTProcessor::importStylesheet() while a transformation is in progress |
| 68 | +destructor: Error: Cannot call XSLTProcessor::importStylesheet() while a transformation is in progress |
| 69 | +string(24) "<?xml version="1.0"?> |
| 70 | +a |
| 71 | +" |
| 72 | +callback: Error: Cannot call XSLTProcessor::importStylesheet() while a transformation is in progress |
| 73 | +destructor: Error: Cannot call XSLTProcessor::importStylesheet() while a transformation is in progress |
| 74 | +string(1) "a" |
| 75 | +callback: Error: Cannot call XSLTProcessor::importStylesheet() while a transformation is in progress |
| 76 | +destructor: Error: Cannot call XSLTProcessor::importStylesheet() while a transformation is in progress |
| 77 | +bool(true) |
| 78 | +bool(true) |
| 79 | +string(31) "<?xml version="1.0"?> |
| 80 | +REPLACED |
| 81 | +" |
0 commit comments