-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix GH-9628: Implicitly removing nodes from \DOMDocument breaks exist…
…ing references Change the way lifetime works in ext/libxml and ext/dom Previously, a node could be freed even when holding a userland reference to it. This resulted in exceptions when trying to access that node after it has been implicitly or explicitly removed. After this patch, a node will only be freed when the last userland reference disappears. Fixes GH-9628. Closes GH-11576.
- Loading branch information
Showing
25 changed files
with
849 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--TEST-- | ||
Delayed freeing attribute declaration | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
$doc = new DOMDocument; | ||
$doc->loadXML(<<<'XML' | ||
<?xml version="1.0"?> | ||
<!DOCTYPE book [ | ||
<!ELEMENT book (#PCDATA)> | ||
<!ATTLIST book | ||
title CDATA #REQUIRED | ||
> | ||
]> | ||
<book title="book title"/> | ||
XML); | ||
echo $doc->saveXML(), "\n"; | ||
// Note: no way to query the attribute declaration, but this at least tests destruction order | ||
$doc->removeChild($doc->doctype); | ||
echo $doc->saveXML(), "\n"; | ||
?> | ||
--EXPECT-- | ||
<?xml version="1.0"?> | ||
<!DOCTYPE book [ | ||
<!ELEMENT book (#PCDATA)> | ||
<!ATTLIST book title CDATA #REQUIRED> | ||
]> | ||
<book title="book title"/> | ||
|
||
<?xml version="1.0"?> | ||
<book title="book title"/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
--TEST-- | ||
Delayed freeing comment node | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
$doc = new DOMDocument; | ||
$comment = $doc->appendChild($doc->createElement('container')) | ||
->appendChild($doc->createComment('my comment')); | ||
echo $doc->saveXML(), "\n"; | ||
$comment->parentNode->remove(); | ||
echo $doc->saveXML(), "\n"; | ||
echo $doc->saveXML($comment), "\n"; | ||
var_dump($comment->parentNode); | ||
?> | ||
--EXPECT-- | ||
<?xml version="1.0"?> | ||
<container><!--my comment--></container> | ||
|
||
<?xml version="1.0"?> | ||
|
||
<!--my comment--> | ||
NULL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
--TEST-- | ||
Tests with direction construction | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
function node_alike_test($test) { | ||
try { | ||
var_dump($test->parentNode); | ||
var_dump($test->nodeValue); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
try { | ||
var_dump($test->appendChild($test)); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
} | ||
|
||
echo "-- Test DOMCharacterData --\n"; | ||
$test = new DOMCharacterData("test"); | ||
try { | ||
var_dump($test->textContent); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
try { | ||
var_dump($test->appendData('test')); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
echo "-- Test DOMCdataSection --\n"; | ||
$test = new DOMCdataSection("test"); | ||
var_dump($test->textContent); | ||
var_dump($test->appendData('test')); | ||
|
||
echo "-- Test DOMText --\n"; | ||
$test = new DOMText("test"); | ||
try { | ||
var_dump($test->wholeText); | ||
var_dump($test->parentNode); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
try { | ||
var_dump($test->isWhitespaceInElementContent()); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
echo "-- Test DOMComment --\n"; | ||
$test = new DOMComment("my comment"); | ||
var_dump($test->textContent); | ||
var_dump($test->parentNode); | ||
var_dump($test->getLineNo()); | ||
|
||
echo "-- Test DOMElement --\n"; | ||
$test = new DOMElement("qualifiedName", "test"); | ||
var_dump($test->textContent); | ||
var_dump($test->parentNode); | ||
try { | ||
var_dump($test->appendChild($test)); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
echo "-- Test DOMNode --\n"; | ||
node_alike_test(new DOMNode()); | ||
|
||
echo "-- Test DOMNotation --\n"; | ||
node_alike_test(new DOMNotation()); | ||
|
||
echo "-- Test DOMProcessingInstruction --\n"; | ||
node_alike_test(new DOMProcessingInstruction("name", "value")); | ||
|
||
echo "-- Test DOMEntity --\n"; | ||
$test = new DOMEntity(); | ||
try { | ||
var_dump($test->nodeValue); | ||
var_dump($test->parentNode); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
try { | ||
var_dump($test->appendChild($test)); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
echo "-- Test DOMAttr --\n"; | ||
$test = new DOMAttr("attr", "value"); | ||
var_dump($test->nodeValue); | ||
var_dump($test->parentNode); | ||
try { | ||
var_dump($test->appendChild($test)); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
?> | ||
--EXPECT-- | ||
-- Test DOMCharacterData -- | ||
Invalid State Error | ||
Couldn't fetch DOMCharacterData | ||
-- Test DOMCdataSection -- | ||
string(4) "test" | ||
bool(true) | ||
-- Test DOMText -- | ||
string(4) "test" | ||
NULL | ||
bool(false) | ||
-- Test DOMComment -- | ||
string(10) "my comment" | ||
NULL | ||
int(0) | ||
-- Test DOMElement -- | ||
string(4) "test" | ||
NULL | ||
No Modification Allowed Error | ||
-- Test DOMNode -- | ||
Invalid State Error | ||
Couldn't fetch DOMNode | ||
-- Test DOMNotation -- | ||
Invalid State Error | ||
Couldn't fetch DOMNotation | ||
-- Test DOMProcessingInstruction -- | ||
NULL | ||
string(5) "value" | ||
bool(false) | ||
-- Test DOMEntity -- | ||
Invalid State Error | ||
Couldn't fetch DOMEntity | ||
-- Test DOMAttr -- | ||
string(5) "value" | ||
NULL | ||
No Modification Allowed Error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--TEST-- | ||
Delayed freeing document fragment | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
$doc = new DOMDocument; | ||
$frag = $doc->createDocumentFragment(); | ||
$frag->appendChild($doc->createElementNS('some:ns', 'child', 'text content')); | ||
$child = $doc->appendChild($doc->createElement('root'))->appendChild($frag); | ||
var_dump($doc->textContent); | ||
$doc->documentElement->remove(); | ||
var_dump($doc->textContent); | ||
unset($doc); | ||
var_dump($child->textContent); | ||
|
||
$doc = new DOMDocument; | ||
$doc->appendChild($doc->createElement('container')); | ||
$doc->documentElement->appendChild($doc->importNode($frag)); | ||
unset($frag); | ||
var_dump($doc->textContent); | ||
|
||
var_dump($child->parentNode); | ||
?> | ||
--EXPECTF-- | ||
string(12) "text content" | ||
string(0) "" | ||
string(12) "text content" | ||
|
||
Warning: DOMNode::appendChild(): Document Fragment is empty in %s on line %d | ||
string(0) "" | ||
NULL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
--TEST-- | ||
Delayed freeing character data | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
$doc = new DOMDocument; | ||
$doc->loadXML(<<<'XML' | ||
<?xml version="1.0"?> | ||
<container><![CDATA[This is a CDATA section<p>test</p>]]></container> | ||
XML); | ||
$cdata = $doc->documentElement->firstChild; | ||
var_dump($cdata->wholeText, $cdata->parentNode->tagName); | ||
$cdata->parentNode->remove(); | ||
var_dump($cdata->wholeText, $cdata->parentNode->tagName); | ||
?> | ||
--EXPECTF-- | ||
string(34) "This is a CDATA section<p>test</p>" | ||
string(9) "container" | ||
|
||
Warning: Attempt to read property "tagName" on null in %s on line %d | ||
string(34) "This is a CDATA section<p>test</p>" | ||
NULL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--TEST-- | ||
Delayed freeing dtd node | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
$doc = new DOMDocument; | ||
$dtd = $doc->implementation->createDocumentType('qualified name', 'public', 'system'); | ||
$doc = $doc->implementation->createDocument('', '', $dtd); | ||
echo $doc->saveXML(), "\n"; | ||
unset($doc); | ||
echo $dtd->ownerDocument->saveXML(); | ||
$dtd->ownerDocument->removeChild($dtd); | ||
var_dump($dtd->ownerDocument->nodeName); | ||
?> | ||
--EXPECT-- | ||
<?xml version="1.0"?> | ||
<!DOCTYPE qualified name PUBLIC "public" "system"> | ||
|
||
<?xml version="1.0"?> | ||
<!DOCTYPE qualified name PUBLIC "public" "system"> | ||
string(9) "#document" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--TEST-- | ||
Delayed freeing element declaration | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
$doc = new DOMDocument; | ||
$doc->loadXML(<<<'XML' | ||
<?xml version="1.0"?> | ||
<!DOCTYPE books [ | ||
<!ELEMENT parent (child1, child2)> | ||
<!ELEMENT child1 (#PCDATA)> | ||
<!ELEMENT child2 (#PCDATA)> | ||
]> | ||
<container><parent/></container> | ||
XML, LIBXML_NOENT); | ||
$element = $doc->documentElement->firstElementChild; | ||
echo $doc->saveXML(), "\n"; | ||
var_dump($element->tagName); | ||
var_dump($element->textContent); | ||
|
||
$doc->removeChild($doc->doctype); | ||
echo $doc->saveXML(), "\n"; | ||
var_dump($element->tagName); | ||
var_dump($element->textContent); | ||
?> | ||
--EXPECT-- | ||
<?xml version="1.0"?> | ||
<!DOCTYPE books [ | ||
<!ELEMENT parent (child1 , child2)> | ||
<!ELEMENT child1 (#PCDATA)> | ||
<!ELEMENT child2 (#PCDATA)> | ||
]> | ||
<container><parent/></container> | ||
|
||
string(6) "parent" | ||
string(0) "" | ||
<?xml version="1.0"?> | ||
<container><parent/></container> | ||
|
||
string(6) "parent" | ||
string(0) "" |
Oops, something went wrong.