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

From: Date: Sat, 24 Oct 2026 17:15:30 +0000
Subject: [php-src] master: Merge branch 'PHP-8.5' into PHP-8.6
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-142687@lists.php.net to get a copy of this message
Author: ndossche (ndossche) Date: 2026-10-24T19:15:12+02:00 Commit: https://github.com/php/php-src/commit/6a74b16d272b88225c06e01db71500de6a469e72 Raw diff: https://github.com/php/php-src/commit/6a74b16d272b88225c06e01db71500de6a469e72.diff Merge branch 'PHP-8.5' into PHP-8.6 * PHP-8.5: 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 cc1a91395056..60b56df5a6ce 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,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) + - Hash: . Fix GOST and Snefru digests of 512 MiB or more. (Martin Mirchev) 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 0d6b320dd0ef..72381ae4c5b4 100644 --- a/ext/dom/xml_serializer.c +++ b/ext/dom/xml_serializer.c @@ -1226,18 +1226,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 (#142687) next »