[php-src] Issue #9628: Implicitly removing nodes from \DOMDocument breaks existing references

From: 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)

« previous php.bugs (#242480) next »