From 76748c7b01e6e513a3c5af829caeefd117420662 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Wed, 8 Jul 2026 02:01:54 +0800 Subject: [PATCH 1/3] ext/dom: Fix Dom\DtdNamedNodeMap index overflow in dimension access --- NEWS | 3 ++ ext/dom/dom_iterators.c | 12 +++++- ext/dom/php_dom.h | 2 +- ...edNodeMap_dimension_index_overflow_64.phpt | 37 +++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt diff --git a/NEWS b/NEWS index 8971e7d317a3..63100e067eac 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,9 @@ PHP NEWS - DOM: . Fixed bug GH-22570 (Stack overflow when serializing a deeply nested Dom\XMLDocument). (iliaal) + . Fixed Dom\DtdNamedNodeMap dimension access to throw for indexes outside the + int range instead of overflowing while converting to int. + (Weilin Du) - Exif: . Fixed bug GH-11020 (exif_read_data() emits a spurious "Illegal IFD size" diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index f97a9ec825d5..7566dd8b61a8 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -79,14 +79,22 @@ void dom_free_notation(xmlEntityPtr entity) /* {{{ */ } /* }}} */ -xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, int index) +xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, zend_long index) { int htsize; + if (index < 0) { + return NULL; + } + if (UNEXPECTED(ZEND_LONG_INT_OVFL(index))) { + zend_value_error("must be between 0 and %d", INT_MAX); + return NULL; + } + if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) { nodeIterator iter; iter.cur = 0; - iter.index = index; + iter.index = (int) index; iter.node = NULL; xmlHashScan(ht, itemHashScanner, &iter); return iter.node; diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 1b19aeee3baa..6f4b5075b659 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -127,7 +127,7 @@ bool dom_node_is_read_only(const xmlNode *node); bool dom_node_children_valid(const xmlNode *node); xmlNodePtr create_notation(xmlDtdPtr parent_dtd, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); void dom_free_notation(xmlEntityPtr entity); -xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index); +xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, zend_long index); zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref); void dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece, zend_class_entry *ce); xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr original, zval *return_value, dom_object *parent_intern); diff --git a/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt b/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt new file mode 100644 index 000000000000..0d9447ea004a --- /dev/null +++ b/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt @@ -0,0 +1,37 @@ +--TEST-- +Dom\DtdNamedNodeMap dimension access throws for indexes outside the int range +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- + + +]> + +XML); + +$overflow = 4294967296; + +function dump_access(Closure $callback): void { + try { + var_dump($callback()?->nodeName); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } +} + +dump_access(fn() => $doc->doctype->entities[$overflow]); + +dump_access(fn() => $doc->doctype->notations[$overflow]); +?> +--EXPECT-- +must be between 0 and 2147483647 +must be between 0 and 2147483647 From bff95033d0b9e72977fa36be52ac9f7ce0a7f06b Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Wed, 8 Jul 2026 02:11:14 +0800 Subject: [PATCH 2/3] fix NEWS --- NEWS | 4 ++-- ext/dom/dom_iterators.c | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 63100e067eac..aaf4680b42a7 100644 --- a/NEWS +++ b/NEWS @@ -20,8 +20,8 @@ PHP NEWS - DOM: . Fixed bug GH-22570 (Stack overflow when serializing a deeply nested Dom\XMLDocument). (iliaal) - . Fixed Dom\DtdNamedNodeMap dimension access to throw for indexes outside the - int range instead of overflowing while converting to int. + . Fixed Dom\DtdNamedNodeMap dimension access to throw ValueError for indexes + outside the int range instead of overflowing while converting to int. (Weilin Du) - Exif: diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index 7566dd8b61a8..cb4b47c75899 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -83,9 +83,6 @@ xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, zend_long index) { int htsize; - if (index < 0) { - return NULL; - } if (UNEXPECTED(ZEND_LONG_INT_OVFL(index))) { zend_value_error("must be between 0 and %d", INT_MAX); return NULL; From 0c779e090ae8444ba30b07d767dc120cd9c771bd Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Wed, 8 Jul 2026 14:45:24 +0800 Subject: [PATCH 3/3] fix negative values --- NEWS | 6 +++--- ext/dom/dom_iterators.c | 3 +++ .../xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index aaf4680b42a7..cd396479e3e2 100644 --- a/NEWS +++ b/NEWS @@ -20,9 +20,9 @@ PHP NEWS - DOM: . Fixed bug GH-22570 (Stack overflow when serializing a deeply nested Dom\XMLDocument). (iliaal) - . Fixed Dom\DtdNamedNodeMap dimension access to throw ValueError for indexes - outside the int range instead of overflowing while converting to int. - (Weilin Du) + . Fixed Dom\DtdNamedNodeMap integer dimension access so negative indexes + return NULL and indexes outside the int range throw ValueError instead of + returning the first entity or notation. (Weilin Du) - Exif: . Fixed bug GH-11020 (exif_read_data() emits a spurious "Illegal IFD size" diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index cb4b47c75899..7566dd8b61a8 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -83,6 +83,9 @@ xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, zend_long index) { int htsize; + if (index < 0) { + return NULL; + } if (UNEXPECTED(ZEND_LONG_INT_OVFL(index))) { zend_value_error("must be between 0 and %d", INT_MAX); return NULL; diff --git a/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt b/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt index 0d9447ea004a..cc2d7a06a2ca 100644 --- a/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt +++ b/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt @@ -1,5 +1,5 @@ --TEST-- -Dom\DtdNamedNodeMap dimension access throws for indexes outside the int range +Dom\DtdNamedNodeMap dimension access handles invalid integer indexes --EXTENSIONS-- dom --SKIPIF-- @@ -28,10 +28,14 @@ function dump_access(Closure $callback): void { } } +dump_access(fn() => $doc->doctype->entities[-1]); dump_access(fn() => $doc->doctype->entities[$overflow]); +dump_access(fn() => $doc->doctype->notations[-1]); dump_access(fn() => $doc->doctype->notations[$overflow]); ?> --EXPECT-- +NULL must be between 0 and 2147483647 +NULL must be between 0 and 2147483647