There are two linked issues:
- Conflicts couldn't be resolved by changing the prefix name.
- Lacking a prefix would shift the namespace as the default namespace,
causing elements to suddenly become part of the namespace instead of
the attributes.
The output could still be improved by removing redundant namespace
declarations, but that's another issue. At least the output is
correct now.
Closes GH-11777.
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.
* Remove obsolete workaround code
This code was for libxml2 <= 2.6.14. PHP requires at least libxml2
2.9.0.
* Use an inline check instead of calling into the library for an empty string check
When you construct a DOM tree containing subtrees which are constructed
top-down, this won't remove the redundant namespaces. That's because the
following conditions hold:
1) The namespace are reused from the doc->oldNs list.
2) Therefore during reconciliation no nsDef field is set, so no redundant
namespaces are removed by our reconciliation code.
Furthermore, it would only be fixed up automatically if the tree wasn't
added in bottom-up way, or if it had been constructed bottom-up from the
start.
Fix it by setting a flag to remove redundant namespaces in the libxml2
reconciliation call.
Since removing redundant namespaces may have a performance cost, we only do
this after performing a simple check.
Closes GH-11528.
* PHP-8.2:
Fix GH-11455: Segmentation fault with custom object date properties
Revert "Fix GH-11404: DOMDocument::savexml and friends ommit xmlns="" declaration for null namespace, creating incorrect xml representation of the DOM"
* PHP-8.1:
Revert "Fix GH-11404: DOMDocument::savexml and friends ommit xmlns="" declaration for null namespace, creating incorrect xml representation of the DOM"
This reverts commit 7eb3e9cd17.
Although the fix follows the spec, it causes issues because a lot of old
code assumes the incorrect behaviour PHP had since a long time.
We cannot do this yet, especially not in a stable release.
We revert this for the time being.
See GH-11428.
The problem is the usage of zval_get_long(). In particular, if the
string is non-numeric the result of zval_get_long() will be 0 without
giving an error or warning. This is misleading for users: users get the
impression that they can use strings to access the map because it
coincidentally works for the first item (which is at index 0). Of
course, this fails with any other index which causes confusion and bugs.
This patch adds proper support for using string offsets while accessing
the map. It does so by detecting if it's a non-numeric string, and then
using the getNamedItem() method instead of item(). I had to split up the
array access implementation code for DOMNodeList and DOMNamedNodeMap
first to be able to do this.
Closes GH-11468.
* PHP-8.2:
Fix GH-11404: DOMDocument::savexml and friends ommit xmlns="" declaration for null namespace, creating incorrect xml representation of the DOM
* PHP-8.1:
Fix GH-11404: DOMDocument::savexml and friends ommit xmlns="" declaration for null namespace, creating incorrect xml representation of the DOM
The NULL namespace is only correct when there is no default namespace
override. When there is, we need to manually set it to the empty string
namespace.
Closes GH-11428.
We'll use the DOM wrapper version of libxml2 instead of the regular one.
It's conforming to the behaviour we expect of DOM.
Most of this patch is tests.
I based and extended the tests on the code attached with the aforementioned
bug reports. Therefore the credits for the tests:
Co-authored-by: hilse at web dot de
Co-authored-by: robin2008 at altruists dot org
Co-authored-by: sgunderson at bigfoot dot com
We'll also change the searching point of the internal reconciliation to
start at the top of the added tree to avoid redundant work now that the
function is changed.
Closes GH-11454.
* PHP-8.2:
Fix GH-11433: Unable to set CURLOPT_ACCEPT_ENCODING to NULL
Fix "invalid state error" with cloned namespace declarations
Fix lifetime issue with getAttributeNodeNS()
* PHP-8.1:
Fix GH-11433: Unable to set CURLOPT_ACCEPT_ENCODING to NULL
Fix "invalid state error" with cloned namespace declarations
Fix lifetime issue with getAttributeNodeNS()
* Fix type confusion and parent reference
* Manually manage the lifetime of the parent
* Add regression tests
* Break out to a helper, and apply the use-after-free fix to xpath
Closes GH-11402.
* Use a prepending strategy instead of appending in dom_set_old_ns()
Looping to the end of the list is wasteful. We can just put the new
nodes at the front of the list. I don't believe we can fully prepend,
because libxml2 may assume that the xml namespace is the first one, so
we'll put the new ones as the second one.
* Reuse namespaces from doc->oldNs if possible in dom_get_ns()
* Add a test for reconciling a reused namespace
* Explain why there can't be a cycle between oldNs and nsDef
Closes GH-11376.
Also fixes#77894.
A few callers remove all children of a node. The way it was done in
node.c was unsafe, because it left nodep->last dangling. It just happens
to not crash if xmlNodeSetContent() is called immediately afterwards.
* PHP-8.2:
Fix bug #77686: Removed elements are still returned by getElementById
Fix bug #81642: DOMChildNode::replaceWith() bug when replacing a node with itself
Fix bug #67440: append_node of a DOMDocumentFragment does not reconcile namespaces
* PHP-8.1:
Fix bug #77686: Removed elements are still returned by getElementById
Fix bug #81642: DOMChildNode::replaceWith() bug when replacing a node with itself
Fix bug #67440: append_node of a DOMDocumentFragment does not reconcile namespaces
The test was amended from the original issue report. For the test:
Co-authored-by: php@deep-freeze.ca
The problem is that the regular dom_reconcile_ns() only works on a
single node. We actually have to reconciliate the whole tree in case a
fragment was added. This also required to move some code around such
that this special case could be handled separately.
Closes GH-11362.
* Implement iteration cache, item cache and length cache for node list iteration
The current implementation follows the spec requirement that the list
must be "live". This means that changes in the document must be
reflected in the existing node lists without requiring the user to
refetch the node list.
The consequence is that getting any item, or the length of the list,
always starts searching from the root element of the node list. This
results in O(n) time to get any item or the length. If there's a for
loop over the node list, this means the iterations will take O(n²) time
in total. This causes real-world performance issues with potential for
downtime (see GH-11308 and its references for details).
We fix this by introducing a caching strategy. We cache the last
iterated object in the iterator, the last requested item in the node
list, and the last length computation. To invalidate the cache, we
simply count the number of modifications made to the containing
document. If the modification number does not match what the number was
during caching, we know the document has been modified and the cache is
invalid. If this ever overflows, we saturate the modification number and
don't do any caching anymore. Note that we don't check for overflow on
64-bit systems because it would take hundreds of years to overflow.
Fixes GH-11308.
I was surprised to see that getting the stricterror property showed in
in the Callgrind profile of some tests. Turns out we sometimes allocate
them. Fix this by returning the default in case no changes were made yet.
Closes GH-11345.
* PHP-8.2:
Fix DOMElement::append() and DOMElement::prepend() hierarchy checks
Fix spec compliance error for DOMDocument::getElementsByTagNameNS
Fix GH-11336: php still tries to unlock the shared memory ZendSem with opcache.file_cache_only=1 but it was never locked
Fix GH-11338: SplFileInfo empty getBasename with more than one slash
* PHP-8.1:
Fix DOMElement::append() and DOMElement::prepend() hierarchy checks
Fix spec compliance error for DOMDocument::getElementsByTagNameNS
Fix GH-11336: php still tries to unlock the shared memory ZendSem with opcache.file_cache_only=1 but it was never locked
Fix GH-11338: SplFileInfo empty getBasename with more than one slash
Spec link: https://dom.spec.whatwg.org/#concept-getelementsbytagnamens
Spec says we should match any namespace when '*' is provided. This was
however not the case: elements that didn't have a namespace were not
returned. This patch fixes the error by modifying the namespace check.
Closes GH-11343.
This reverts commit 94ee4f9834.
The commit was a bit too late to be included in PHP 8.2 RC1. Given it's a massive ABI break, we decide to postpone the change to PHP 8.3.
Object handlers being separate from class entries is a legacy inherited from PHP 5. Today it has little benefit to keep them separate: in fact, accessing object handlers usually requires not-so-safe hacks.
While it is possible to swap handlers in a custom installed create_object handler, this mostly is tedious, as well as it requires allocating the object handlers struct at runtime, possibly caching it etc..
This allows extensions, which intend to observe other classes to install their own class handlers.
The life cycle of internal classes may now be simply observed by swapping the class handlers in post_startup stage.
The life cycle of userland classes may be observed by iterating over the new classes in zend_compile_file and zend_compile_string and then swapping their handlers.
In general, this would also be a first step in directly tying the object handlers to classes. Especially given that I am not aware of any case where the object handlers would be different between various instances of a given class.
Signed-off-by: Bob Weinand <bobwei9@hotmail.com>
- for packed arrays we store just an array of zvals without keys.
- the elements of packed array are accessible throuf as ht->arPacked[i]
instead of ht->arData[i]
- in addition to general ZEND_HASH_FOREACH_* macros, we introduced similar
familied for packed (ZEND_HASH_PACKED_FORECH_*) and real hashes
(ZEND_HASH_MAP_FOREACH_*)
- introduced an additional family of macros to access elements of array
(packed or real hashes) ZEND_ARRAY_ELEMET_SIZE, ZEND_ARRAY_ELEMET_EX,
ZEND_ARRAY_ELEMET, ZEND_ARRAY_NEXT_ELEMENT, ZEND_ARRAY_PREV_ELEMENT
- zend_hash_minmax() prototype was changed to compare only values
Because of smaller data set, this patch may show performance improvement
on some apps and benchmarks that use packed arrays. (~1% on PHP-Parser)
TODO:
- sapi/phpdbg needs special support for packed arrays (WATCH_ON_BUCKET).
- zend_hash_sort_ex() may require converting packed arrays to hash.