[php-src] Issue #9628: Implicitly removing nodes from \DOMDocument breaks existing references
| From: | dtdesign | Date: | Wed, 28 Sep 2022 11:36:51 +0000 |
| Subject: | [php-src] Issue #9628: Implicitly removing nodes from \DOMDocument breaks existing references | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-242480@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/9628
Author: dtdesign
### Description
The following code:
```php
<?php
$html = <<<'HTML'
<p>
<span>
<strong>
<span>
Test
</span>
</strong>
</span>
</p>
HTML;
$doc = new \DOMDocument('1.0', 'UTF-8');
$doc->loadHTML(
'<html><head><meta http-equiv="Content-Type"
content="text/html; charset=utf-8" /></head><body>' . $html .
'</body></html>'
);
$xpath = new \DOMXPath($doc);
$spans = [];
foreach ($xpath->query('//span') as $span) {
$spans[] = $span;
}
\assert(\count($spans) === 2);
foreach ($spans as $span) {
\assert($span instanceof \DOMElement);
\assert($span->ownerDocument === $doc);
}
foreach ($spans as $span) {
\assert($span instanceof \DOMElement);
// This call will fail for the second
<span>. It does not really
// matter what is accessed here, the error message will be the same.
$span->hasAttribute('test');
while ($span->childNodes->length) {
$span->removeChild($span->childNodes[0]);
}
$span->appendChild(
$span->ownerDocument->createTextNode('Hello World')
);
}
echo $span[0]->textContent . "\n"; // Hello World
```
Resulted in this output:
```
Fatal error: Uncaught Error: Couldn't fetch DOMElement in
/opt/homebrew/var/www/test/dom-not-found.php:36 Stack trace: #0
/opt/homebrew/var/www/test/dom-not-found.php(36): DOMElement->hasAttribute('test') #1
{main} thrown in /opt/homebrew/var/www/test/dom-not-found.php on line 36
```
But I expected this output instead:
```
Hello World
```
The problem was also reproduced on https://3v4l.org/uSEC9 and
yields the identical error message for PHP 7.4.0 - 8.2rc1 (EOL version have not been tested).
Removing the intermediate <strong> will cause the script to work, it appears that
the implicit removal of the inner <span> by removing its parent is the cause of
the issue.
Even worse, it is impossible to detect this kind of problem without resorting to a try { … }
catch (\Error $e) { … } construct, because any access to the “defective” reference will
yield the error. From my understanding of the documentations there is \DOMException and
the \DOM_* error constants that should be yielded instead, so there is possibly a
secondary bug hiding in this issue.
### PHP Version
8.1.10
### Operating System
macOS 12.6 (aarch64)