[php-src] PHP-8.6: Merge branch 'PHP-8.4' into PHP-8.5

From: Date: Sat, 24 Oct 2026 17:15:25 +0000
Subject: [php-src] PHP-8.6: Merge branch 'PHP-8.4' into PHP-8.5
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-142688@lists.php.net to get a copy of this message
Author: ndossche (ndossche) Date: 2026-10-24T19:14:53+02:00 Commit: https://github.com/php/php-src/commit/19aeda2d9697eef46395b765e39d8ed4c937d5df Raw diff: https://github.com/php/php-src/commit/19aeda2d9697eef46395b765e39d8ed4c937d5df.diff Merge branch 'PHP-8.4' into PHP-8.5 * PHP-8.4: Fix error paths in dom_xml_serializing_a_document_node() Changed paths: A ext/dom/tests/modern/xml/serialize_document_write_failure.phpt A ext/dom/tests/modern/xml/serialize_document_write_mutation.phpt M NEWS M ext/dom/xml_serializer.c Diff: diff --git a/NEWS b/NEWS index 2518d1cabee7..0b6e155d3f27 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,9 @@ PHP NEWS . Fixed bug GH-24641 (ndbm backend never checks dbm_open() return value, NULL deref on first use after a failed open). (Girgias) +- DOM: + . Fix error paths in dom_xml_serializing_a_document_node(). (ndossche) + - Fileinfo: . Fixed bug GH-24289 (finfo::file() reports the wrong argument number for an invalid $filename). (Lazizbek Ergashev) diff --git a/ext/dom/tests/modern/xml/serialize_document_write_failure.phpt b/ext/dom/tests/modern/xml/serialize_document_write_failure.phpt new file mode 100644 index 000000000000..2e33cb5420cf --- /dev/null +++ b/ext/dom/tests/modern/xml/serialize_document_write_failure.phpt @@ -0,0 +1,39 @@ +--TEST-- +Dom\XMLDocument: failed write while serializing the document node must not detach its children +--EXTENSIONS-- +dom +--FILE-- +<?php + +class FailingStream { + public $context; + + public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool { + return true; + } + + public function stream_write(string $data): int|false { + return false; + } + + public function stream_tell(): int { + return 0; + } +} + +stream_wrapper_register('failing', FailingStream::class); + +$doc = Dom\XMLDocument::createFromString('<root><child/></root>'); +var_dump($doc->saveXmlFile('failing://out')); + +var_dump($doc->documentElement?->nodeName); +var_dump($doc->childNodes->length); +echo $doc->saveXml(); + +?> +--EXPECT-- +bool(false) +string(4) "root" +int(1) +<?xml version="1.0" encoding="UTF-8"?> +<root><child/></root> diff --git a/ext/dom/tests/modern/xml/serialize_document_write_mutation.phpt b/ext/dom/tests/modern/xml/serialize_document_write_mutation.phpt new file mode 100644 index 000000000000..66127130ecff --- /dev/null +++ b/ext/dom/tests/modern/xml/serialize_document_write_mutation.phpt @@ -0,0 +1,40 @@ +--TEST-- +Dom\XMLDocument: mutating the document from a stream write during document serialization +--EXTENSIONS-- +dom +--FILE-- +<?php + +class MutatingStream { + public $context; + public static $doc; + + public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool { + return true; + } + + public function stream_write(string $data): int { + if (self::$doc !== null) { + $doc = self::$doc; + self::$doc = null; + $doc->append($doc->createComment('injected')); + } + return strlen($data); + } +} + +stream_wrapper_register('mutating', MutatingStream::class); + +$doc = Dom\XMLDocument::createFromString('<root><child/></root>'); +MutatingStream::$doc = $doc; +$doc->saveXmlFile('mutating://out'); + +$doc->append($doc->createComment('after')); +var_dump($doc->childNodes->length); +echo $doc->saveXml(), "\n"; + +?> +--EXPECT-- +int(3) +<?xml version="1.0" encoding="UTF-8"?> +<root><child/></root><!--injected--><!--after--> diff --git a/ext/dom/xml_serializer.c b/ext/dom/xml_serializer.c index 2d9e55a7b706..bd7e8bf6aa8d 100644 --- a/ext/dom/xml_serializer.c +++ b/ext/dom/xml_serializer.c @@ -1228,18 +1228,18 @@ static int dom_xml_serializing_a_document_node( /* 1. Let serialized document be an empty string. * => We use the output buffer instead. */ - xmlNodePtr child = node->children; - node->children = NULL; - /* https://github.com/w3c/DOM-Parsing/issues/50 */ TRY(xmlOutputBufferFlush(ctx->out)); - TRY(xmlSaveDoc(ctx->ctxt, (xmlDocPtr) node)); + /* To gain the xml declaration, use a shallow copy of the document with the children NULLed out. + * Stream wrappers can access the real document, so we cannot modify that. */ + xmlDoc declaration_doc = *(xmlDocPtr) node; + declaration_doc.children = declaration_doc.last = NULL; + TRY(xmlSaveDoc(ctx->ctxt, &declaration_doc)); TRY(xmlSaveFlush(ctx->ctxt)); - node->children = child; - /* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child passing along the provided arguments, * and append the result to serialized document. */ + xmlNodePtr child = node->children; while (child != NULL) { TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed)); child = child->next;

« previous php.cvs (#142688) next »