insertBefore($n, $n) unlinked the node, then rebuilt its position from the
pointers the unlink had just cleared, leaving it out of the document with a
self-referencing sibling list, freed twice at teardown. Retarget the reference
to the node's next sibling, as the modern DOM already does.
Close GH-23379
Fix#22447
xmlHasProp() matches an attribute by local name only, ignoring its
namespace, whereas xmlAddChild()/xmlAddPrevSibling() dedup an incoming
no-namespace attribute via xmlHasNsProp(..., NULL), which matches only
attributes with no namespace. When both a no-namespace and a namespaced
attribute share a local name, the pre-insertion check unlinked the wrong
(namespaced) attribute, leaving libxml to free the still-wrapped
no-namespace duplicate and producing a use-after-free at request
shutdown.
Use xmlHasNsProp(..., NULL) so the pre-insertion check matches libxml's
internal duplicate detection, as advised by @nwellnhof.
Close GH-22452
Fix#22219
Modern DOM keeps namespace declarations off the tree (node->nsDef is NULL),
so libxml's native validators cannot resolve a prefixed QName appearing in
element or attribute content. Temporarily materialize them as nsDef entries
around schema, RelaxNG and DTD validation, reusing the C14N relink
machinery, then restore the tree.
close GH-22224
For programmatically built documents (e.g. createElementNS), namespaces
live on node->ns without corresponding xmlns attributes. Create temporary
synthetic nsDef entries so C14N can find them, complementing the existing
xmlns attribute to nsDef conversion.
close GH-21561
There are several issues with this macro:
- It is incorrectly named: It's not an empty default case. It's an unreachable
default case.
- It is hiding control flow in its definition, which can be confusing for
humans and tools (such as Coccinelle) alike, because it looks like it would
be a statement that belongs to the "current" case rather than opening a new
one.
Since this macro is exactly as long as explicitly spelling out its definition
(excluding the useless `break;`), it is not even making the code any more
succinct.
The xmlns attribute unlinking code in dom_relink_ns_decls_element was
clobbering attr->prev instead of updating the predecessor's next pointer,
leaving non-first xmlns attributes reachable in the properties list.
C14N then output them both as nsDef entries and as attributes.
close GH-21566
Prior to this patch there was a common read handler, and it relied on
the dom class set in the intern document. However, Dom\Implementation
allows creating DTDs unassociated with a document, so we can't rely on
an intern document and the check fails. This causes the ZVAL_NULL() path
to be taken.
To solve this, just split the handler.
Closes GH-21082.
C14N code expects namespace to be in-tree, but we store namespaces in a
different way out-of-tree to avoid reconciliations that break the tree
structure in a way unexpected by the DOM spec. In the DOM spec,
namespace nodes don't exist; they're regular attributes.
To solve this, we temporarily make fake namespace nodes that we later
remove.
Closes GH-20457.
Many tag names are single characters, so we can use the fast string
construction. In cases where a NULL name is used we can also use the
empty string.
This avoids some allocations and some work.
The code was really messy with lots of checks and inconsistencies.
This splits everything up into different functions and now everything is
relayed to a handler vtable.
* PHP-8.4:
Fix GH-16777: Calling the constructor again on a DOM object after it is in a document causes UAF
Fix GH-16808: Segmentation fault in RecursiveIteratorIterator->current() with a xml element input