From da906ee4f9bf49eb785f372a8fe8bccf76955fdc Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:38:58 +0200 Subject: [PATCH 01/12] phar: Remove duplicated error-handling code (#20137) This is already handled by the switch below. --- ext/phar/phar_object.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index c30145d9fb940..ca19a38b2cfef 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -703,11 +703,6 @@ PHP_METHOD(Phar, webPhar) goto cleanup_fail; } - if (Z_TYPE_P(rewrite_fci.retval) == IS_UNDEF || Z_TYPE(retval) == IS_UNDEF) { - zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false"); - goto cleanup_fail; - } - switch (Z_TYPE(retval)) { case IS_STRING: efree(entry); From f97ee5c71b41771de7aab0fe9c1572f6a5eb656e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:39:32 +0200 Subject: [PATCH 02/12] phar: Reduce code duplication in destructor (#20140) We can make a variant of the macro to control the throwing behaviour. --- ext/phar/phar_object.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index ca19a38b2cfef..0ad7c5d66d759 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -4513,28 +4513,27 @@ PHP_METHOD(PharFileInfo, __construct) } /* }}} */ -#define PHAR_ENTRY_OBJECT() \ +#define PHAR_ENTRY_OBJECT_EX(throw) \ zval *zobj = ZEND_THIS; \ phar_entry_object *entry_obj = (phar_entry_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset); \ if (!entry_obj->entry) { \ - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \ - "Cannot call method on an uninitialized PharFileInfo object"); \ - RETURN_THROWS(); \ + if (throw) { \ + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \ + "Cannot call method on an uninitialized PharFileInfo object"); \ + } \ + return; \ } +#define PHAR_ENTRY_OBJECT() PHAR_ENTRY_OBJECT_EX(true) + /* {{{ clean up directory-based entry objects */ PHP_METHOD(PharFileInfo, __destruct) { - zval *zobj = ZEND_THIS; - phar_entry_object *entry_obj = (phar_entry_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset); - if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } - if (!entry_obj->entry) { - return; - } + PHAR_ENTRY_OBJECT_EX(false); if (entry_obj->entry->is_temp_dir) { if (entry_obj->entry->filename) { From 9c00765d64b32cc7bb9e0096574e52c10dfa0468 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:40:10 +0200 Subject: [PATCH 03/12] phar: Remove obsoleted workaround code (#20136) --- ext/phar/zip.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ext/phar/zip.c b/ext/phar/zip.c index ca536c9c75aae..2d43092e97ae7 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -641,13 +641,6 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia zend_off_t restore_pos = php_stream_tell(fp); php_stream_seek(fp, entry.offset, SEEK_SET); - /* these next lines should be for php < 5.2.6 after 5.3 filters are fixed */ - fp->writepos = 0; - fp->readpos = 0; - php_stream_seek(fp, entry.offset, SEEK_SET); - fp->writepos = 0; - fp->readpos = 0; - /* the above lines should be for php < 5.2.6 after 5.3 filters are fixed */ mydata->alias_len = entry.uncompressed_filesize; if (entry.flags & PHAR_ENT_COMPRESSED_GZ) { From 8e405ca22a1891de3ee23ee3f5f6e2f43871d474 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:28:01 +0200 Subject: [PATCH 04/12] xml: Migrate build_comment to ZendMM --- ext/xml/compat.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ext/xml/compat.c b/ext/xml/compat.c index 21184be87182b..bdec7f97104bb 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -290,17 +290,19 @@ notation_decl_handler(void *user, const xmlChar *notation, const xmlChar *pub_id parser->h_notation_decl(parser->user, notation, NULL, sys_id, pub_id); } -static void -build_comment(const xmlChar *data, size_t data_len, xmlChar **comment, size_t *comment_len) +static xmlChar * +build_comment(const xmlChar *data, size_t data_len, size_t *comment_len) { *comment_len = data_len + 7; - *comment = xmlMalloc(*comment_len + 1); - memcpy(*comment, "", 3); + xmlChar *comment = emalloc(*comment_len + 1); + memcpy(comment, "", 3); + + comment[*comment_len] = '\0'; - (*comment)[*comment_len] = '\0'; + return comment; } static void @@ -309,12 +311,11 @@ comment_handler(void *user, const xmlChar *comment) XML_Parser parser = (XML_Parser) user; if (parser->h_default) { - xmlChar *d_comment; size_t d_comment_len; - build_comment(comment, (size_t) xmlStrlen(comment), &d_comment, &d_comment_len); + xmlChar *d_comment = build_comment(comment, (size_t) xmlStrlen(comment), &d_comment_len); parser->h_default(parser->user, d_comment, d_comment_len); - xmlFree(d_comment); + efree(d_comment); } } From f63b011eee904e768794b4c7b0ac582da13a0c13 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:28:07 +0200 Subject: [PATCH 05/12] xml: Migrate build_entity to ZendMM --- ext/xml/compat.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/xml/compat.c b/ext/xml/compat.c index bdec7f97104bb..c2696386a40bc 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -319,15 +319,16 @@ comment_handler(void *user, const xmlChar *comment) } } -static void -build_entity(const xmlChar *name, size_t len, xmlChar **entity, size_t *entity_len) +static xmlChar * +build_entity(const xmlChar *name, size_t len, size_t *entity_len) { *entity_len = len + 2; - *entity = xmlMalloc(*entity_len + 1); - (*entity)[0] = '&'; - memcpy(*entity+1, name, len); - (*entity)[len+1] = ';'; - (*entity)[*entity_len] = '\0'; + xmlChar *entity = emalloc(*entity_len + 1); + entity[0] = '&'; + memcpy(entity + 1, name, len); + entity[len + 1] = ';'; + entity[*entity_len] = '\0'; + return entity; } static void @@ -362,12 +363,11 @@ get_entity(void *user, const xmlChar *name) if (ret == NULL || ret->etype == XML_INTERNAL_GENERAL_ENTITY || ret->etype == XML_INTERNAL_PARAMETER_ENTITY || ret->etype == XML_INTERNAL_PREDEFINED_ENTITY) { /* Predefined entities will expand unless no cdata handler is present */ if (parser->h_default && ! (ret && ret->etype == XML_INTERNAL_PREDEFINED_ENTITY && parser->h_cdata)) { - xmlChar *entity; size_t len; - build_entity(name, (size_t) xmlStrlen(name), &entity, &len); + xmlChar *entity = build_entity(name, (size_t) xmlStrlen(name), &len); parser->h_default(parser->user, (const xmlChar *) entity, len); - xmlFree(entity); + efree(entity); } else { /* expat will not expand internal entities if default handler is present otherwise it will expand and pass them to cdata handler */ From c9c904f8168acc70ab874c2ea8eb381005b1a07a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:29:47 +0200 Subject: [PATCH 06/12] xml: Migrate _ns_separator to ZendMM --- ext/xml/compat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/xml/compat.c b/ext/xml/compat.c index c2696386a40bc..5f1dbb1c10150 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -465,7 +465,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m /* Note: sax2 flag will be set due to the magic number in `initialized` in php_xml_compat_handlers */ ZEND_ASSERT(parser->parser->sax->initialized == XML_SAX2_MAGIC); parser->use_namespace = 1; - parser->_ns_separator = xmlStrdup(sep); + parser->_ns_separator = BAD_CAST estrdup((const char *) sep); } else { /* Reset flag as XML_SAX2_MAGIC is needed for xmlCreatePushParserCtxt so must be set in the handlers */ @@ -718,7 +718,7 @@ XML_ParserFree(XML_Parser parser) { if (parser->use_namespace) { if (parser->_ns_separator) { - xmlFree(parser->_ns_separator); + efree(parser->_ns_separator); } } if (parser->parser->myDoc) { From 20cc3a35e5ffd977979b57042e147b2bfe4832ba Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:36:43 +0200 Subject: [PATCH 07/12] xml: Migrate start_element_handler to ZendMM --- ext/xml/compat.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/ext/xml/compat.c b/ext/xml/compat.c index 5f1dbb1c10150..92aca782f1b09 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -18,6 +18,7 @@ #if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT) #include "expat_compat.h" #include "ext/libxml/php_libxml.h" +#include "Zend/zend_smart_string.h" #ifdef LIBXML_EXPAT_COMPAT @@ -38,31 +39,31 @@ static void start_element_handler(void *user, const xmlChar *name, const xmlChar **attributes) { XML_Parser parser = (XML_Parser) user; - xmlChar *qualified_name = NULL; if (parser->h_start_element == NULL) { if (parser->h_default) { int attno = 0; + smart_string qualified_name = {0}; + + smart_string_appendc(&qualified_name, '<'); + smart_string_appends(&qualified_name, (const char *) name); - qualified_name = xmlStrncatNew((xmlChar *)"<", name, xmlStrlen(name)); if (attributes) { while (attributes[attno] != NULL) { - int att_len; - char *att_string, *att_name, *att_value; - - att_name = (char *)attributes[attno++]; - att_value = (char *)attributes[attno++]; - - att_len = spprintf(&att_string, 0, " %s=\"%s\"", att_name, att_value); - - qualified_name = xmlStrncat(qualified_name, (xmlChar *)att_string, att_len); - efree(att_string); + const char *att_name = (const char *) attributes[attno++]; + const char *att_value = (const char *) attributes[attno++]; + + smart_string_appendc(&qualified_name, ' '); + smart_string_appends(&qualified_name, att_name); + smart_string_appends(&qualified_name, "=\""); + smart_string_appends(&qualified_name, att_value); + smart_string_appendc(&qualified_name, '"'); } - } - qualified_name = xmlStrncat(qualified_name, (xmlChar *)">", 1); - parser->h_default(parser->user, (const XML_Char *) qualified_name, xmlStrlen(qualified_name)); - xmlFree(qualified_name); + smart_string_appendc(&qualified_name, '>'); + smart_string_0(&qualified_name); + parser->h_default(parser->user, (const XML_Char *) qualified_name.c, qualified_name.len); + smart_string_free(&qualified_name); } return; } From e0561f0c8ef43fe1a379633938bdcd99c0223b82 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:43:26 +0200 Subject: [PATCH 08/12] xml: Migrate qualify_namespace to ZendMM --- ext/xml/compat.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/ext/xml/compat.c b/ext/xml/compat.c index 92aca782f1b09..df764f1c48999 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -22,16 +22,18 @@ #ifdef LIBXML_EXPAT_COMPAT -static void -qualify_namespace(XML_Parser parser, const xmlChar *name, const xmlChar *URI, xmlChar **qualified) +static xmlChar * +qualify_namespace(XML_Parser parser, const xmlChar *name, const xmlChar *URI) { if (URI) { - /* Use libxml functions otherwise its memory deallocation is screwed up */ - *qualified = xmlStrdup(URI); - *qualified = xmlStrncat(*qualified, parser->_ns_separator, 1); - *qualified = xmlStrncat(*qualified, name, xmlStrlen(name)); + smart_string str = {0}; + smart_string_appends(&str, (const char *) URI); + smart_string_appends(&str, (const char *) parser->_ns_separator); + smart_string_appends(&str, (const char *) name); + smart_string_0(&str); + return BAD_CAST str.c; } else { - *qualified = xmlStrdup(name); + return BAD_CAST estrdup((const char *) name); } } @@ -151,7 +153,7 @@ start_element_handler_ns(void *user, const xmlChar *name, const xmlChar *prefix, } return; } - qualify_namespace(parser, name, URI, &qualified_name); + qualified_name = qualify_namespace(parser, name, URI); if (attributes != NULL) { xmlChar *qualified_name_attr = NULL; @@ -160,12 +162,12 @@ start_element_handler_ns(void *user, const xmlChar *name, const xmlChar *prefix, for (i = 0; i < nb_attributes; i += 1) { if (attributes[y+1] != NULL) { - qualify_namespace(parser, attributes[y] , attributes[y + 2], &qualified_name_attr); + qualified_name_attr = qualify_namespace(parser, attributes[y] , attributes[y + 2]); } else { - qualified_name_attr = xmlStrdup(attributes[y]); + qualified_name_attr = BAD_CAST estrdup((const char *) attributes[y]); } attrs[z] = qualified_name_attr; - attrs[z + 1] = xmlStrndup(attributes[y + 3] , (int) (attributes[y + 4] - attributes[y + 3])); + attrs[z + 1] = BAD_CAST estrndup((const char *) attributes[y + 3], attributes[y + 4] - attributes[y + 3]); z += 2; y += 5; } @@ -175,11 +177,11 @@ start_element_handler_ns(void *user, const xmlChar *name, const xmlChar *prefix, parser->h_start_element(parser->user, (const XML_Char *) qualified_name, (const XML_Char **) attrs); if (attrs) { for (i = 0; i < z; i++) { - xmlFree(attrs[i]); + efree(attrs[i]); } efree(attrs); } - xmlFree(qualified_name); + efree(qualified_name); } static void @@ -223,11 +225,11 @@ end_element_handler_ns(void *user, const xmlChar *name, const xmlChar * prefix, return; } - qualify_namespace(parser, name, URI, &qualified_name); + qualified_name = qualify_namespace(parser, name, URI); parser->h_end_element(parser->user, (const XML_Char *) qualified_name); - xmlFree(qualified_name); + efree(qualified_name); } static void From 677c7fe31bd2380c798c107e83b695bc24fc16a4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:50:24 +0200 Subject: [PATCH 09/12] xml: Migrate start_element_handler_ns to ZendMM --- ext/xml/compat.c | 60 ++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/ext/xml/compat.c b/ext/xml/compat.c index df764f1c48999..6ce0809cd5b09 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -93,63 +93,57 @@ start_element_handler_ns(void *user, const xmlChar *name, const xmlChar *prefix, if (parser->h_start_element == NULL) { if (parser->h_default) { - + smart_string qualified_name = {0}; + smart_string_appendc(&qualified_name, '<'); if (prefix) { - qualified_name = xmlStrncatNew((xmlChar *)"<", prefix, xmlStrlen(prefix)); - qualified_name = xmlStrncat(qualified_name, (xmlChar *)":", 1); - qualified_name = xmlStrncat(qualified_name, name, xmlStrlen(name)); - } else { - qualified_name = xmlStrncatNew((xmlChar *)"<", name, xmlStrlen(name)); + smart_string_appends(&qualified_name, (const char *) prefix); + smart_string_appendc(&qualified_name, ':'); } + smart_string_appends(&qualified_name, (const char *) name); if (namespaces) { int i, j; for (i = 0,j = 0;j < nb_namespaces;j++) { - int ns_len; - char *ns_string, *ns_prefix, *ns_url; - - ns_prefix = (char *) namespaces[i++]; - ns_url = (char *) namespaces[i++]; + const char *ns_prefix = (const char *) namespaces[i++]; + const char *ns_url = (const char *) namespaces[i++]; if (ns_prefix) { - ns_len = spprintf(&ns_string, 0, " xmlns:%s=\"%s\"", ns_prefix, ns_url); + smart_string_appends(&qualified_name, " xmlns:"); + smart_string_appends(&qualified_name, ns_prefix); + smart_string_appends(&qualified_name, "=\""); } else { - ns_len = spprintf(&ns_string, 0, " xmlns=\"%s\"", ns_url); + smart_string_appends(&qualified_name, " xmlns=\""); } - qualified_name = xmlStrncat(qualified_name, (xmlChar *)ns_string, ns_len); - efree(ns_string); + smart_string_appends(&qualified_name, ns_url); + smart_string_appendc(&qualified_name, '"'); } } if (attributes) { for (i = 0; i < nb_attributes; i += 1) { - int att_len; - char *att_string, *att_name, *att_value, *att_prefix, *att_valueend; - - att_name = (char *) attributes[y++]; - att_prefix = (char *)attributes[y++]; + const char *att_name = (const char *) attributes[y++]; + const char *att_prefix = (const char *)attributes[y++]; y++; - att_value = (char *)attributes[y++]; - att_valueend = (char *)attributes[y++]; + const char *att_value = (const char *)attributes[y++]; + const char *att_valueend = (const char *)attributes[y++]; + smart_string_appendc(&qualified_name, ' '); if (att_prefix) { - att_len = spprintf(&att_string, 0, " %s:%s=\"", att_prefix, att_name); - } else { - att_len = spprintf(&att_string, 0, " %s=\"", att_name); + smart_string_appends(&qualified_name, att_prefix); + smart_string_appendc(&qualified_name, ':'); } + smart_string_appends(&qualified_name, att_name); + smart_string_appends(&qualified_name, "=\""); - qualified_name = xmlStrncat(qualified_name, (xmlChar *)att_string, att_len); - qualified_name = xmlStrncat(qualified_name, (xmlChar *)att_value, att_valueend - att_value); - qualified_name = xmlStrncat(qualified_name, (xmlChar *)"\"", 1); - - efree(att_string); + smart_string_appendl(&qualified_name, att_value, att_valueend - att_value); + smart_string_appendc(&qualified_name, '"'); } } - qualified_name = xmlStrncat(qualified_name, (xmlChar *)">", 1); - parser->h_default(parser->user, (const XML_Char *) qualified_name, xmlStrlen(qualified_name)); - xmlFree(qualified_name); + smart_string_appendc(&qualified_name, '>'); + parser->h_default(parser->user, (const XML_Char *) qualified_name.c, qualified_name.len); + smart_string_free(&qualified_name); } return; } From bc76b3fca973b3a4548dc339a980d3b714417c55 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 8 Oct 2025 19:22:03 +0200 Subject: [PATCH 10/12] Improve __unserialize() hardening for SplHeap/SplPriorityQueue It was possible to make the heap accept unserialize data when the heap was corrupted or under modification. This adds the necessary check to prevent that from happening. Also, the exception check at the bottom is pointless, spl_heap_unserialize_internal_state() already returns FAILURE on exception. If it *is* necessary, it should be documented why. Closes GH-20109. --- NEWS | 1 + ext/spl/spl_heap.c | 8 ++--- ...lize_under_corruption_or_modification.phpt | 30 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt diff --git a/NEWS b/NEWS index dd60fe29a5b3e..ee76f00c4141a 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ PHP NEWS - SPL: . Fixed bug GH-20101 (SplHeap/SplPriorityQueue serialization exposes INDIRECTs). (nielsdos) + . Improve __unserialize() hardening for SplHeap/SplPriorityQueue. (nielsdos) 09 Oct 2025, PHP 8.5.0RC2 diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 254fbde7b3ff0..5d36266393b04 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -1257,6 +1257,10 @@ PHP_METHOD(SplHeap, __unserialize) Z_PARAM_ARRAY_HT(data) ZEND_PARSE_PARAMETERS_END(); + if (UNEXPECTED(spl_heap_consistency_validations(intern, true) != SUCCESS)) { + RETURN_THROWS(); + } + if (zend_hash_num_elements(data) != 2) { zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name)); RETURN_THROWS(); @@ -1285,10 +1289,6 @@ PHP_METHOD(SplHeap, __unserialize) RETURN_THROWS(); } - if (EG(exception)) { - RETURN_THROWS(); - } - if (UNEXPECTED(spl_heap_consistency_validations(intern, false) != SUCCESS)) { RETURN_THROWS(); } diff --git a/ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt b/ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt new file mode 100644 index 0000000000000..2e54be09ad1a7 --- /dev/null +++ b/ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt @@ -0,0 +1,30 @@ +--TEST-- +SplHeap should not accept unserialize data when it is corrupted or under modification +--FILE-- +__unserialize($array); + return $a < $b ? -1 : ($a == $b ? 0 : 1); + } +} + +$heap = new SplMaxHeap; +$heap->insert(1); +$array = $heap->__serialize(); + +$heap = new MyHeap; +$heap->insert(0); +try { + $heap->insert(2); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Heap cannot be changed when it is already being modified. From 40f4091256f86ff5e65fd88c0f1546129dd512e8 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:52:39 +0200 Subject: [PATCH 11/12] Fix arginfo/zpp violations when LIBXML_SCHEMAS_ENABLED is not available To do this, we move the macro check and therefore we also have to move some variable declarations to avoid compiler warnings. Closes GH-20130. --- NEWS | 4 ++++ ext/xmlreader/php_xmlreader.c | 28 ++++++++++------------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/NEWS b/NEWS index a897bf0b733c6..3f5945f78f289 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ PHP NEWS - Random: . Fix Randomizer::__serialize() w.r.t. INDIRECTs. (nielsdos) +- XMLReader: + . Fix arginfo/zpp violations when LIBXML_SCHEMAS_ENABLED is not available. + (nielsdos) + 23 Oct 2025, PHP 8.3.27 - Core: diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index 7a50b660fb59d..2d7063a938abf 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -468,12 +468,7 @@ static void php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAMETERS, xmlreader_ /* {{{ php_xmlreader_set_relaxng_schema */ static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int type) { -#ifdef LIBXML_SCHEMAS_ENABLED - zval *id; size_t source_len = 0; - int retval = -1; - xmlreader_object *intern; - xmlRelaxNGPtr schema = NULL; char *source; if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &source, &source_len) == FAILURE) { @@ -484,11 +479,13 @@ static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int t zend_argument_value_error(1, "cannot be empty"); RETURN_THROWS(); } - - id = ZEND_THIS; - - intern = Z_XMLREADER_P(id); + +#ifdef LIBXML_SCHEMAS_ENABLED + xmlreader_object *intern = Z_XMLREADER_P(ZEND_THIS); if (intern->ptr) { + int retval = -1; + xmlRelaxNGPtr schema = NULL; + if (source) { schema = _xmlreader_get_relaxNG(source, source_len, type, NULL, NULL); if (schema) { @@ -926,11 +923,7 @@ PHP_METHOD(XMLReader, readString) /* {{{ Use W3C XSD schema to validate the document as it is processed. Activation is only possible before the first Read(). */ PHP_METHOD(XMLReader, setSchema) { -#ifdef LIBXML_SCHEMAS_ENABLED - zval *id; size_t source_len = 0; - int retval = -1; - xmlreader_object *intern; char *source; if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &source, &source_len) == FAILURE) { @@ -941,13 +934,12 @@ PHP_METHOD(XMLReader, setSchema) zend_argument_value_error(1, "cannot be empty"); RETURN_THROWS(); } - - id = ZEND_THIS; - - intern = Z_XMLREADER_P(id); + +#ifdef LIBXML_SCHEMAS_ENABLED + xmlreader_object *intern = Z_XMLREADER_P(ZEND_THIS); if (intern && intern->ptr) { PHP_LIBXML_SANITIZE_GLOBALS(schema); - retval = xmlTextReaderSchemaValidate(intern->ptr, source); + int retval = xmlTextReaderSchemaValidate(intern->ptr, source); PHP_LIBXML_RESTORE_GLOBALS(schema); if (retval == 0) { From 82125936942545ed5f15767f8739db9188745dee Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:59:30 +0200 Subject: [PATCH 12/12] phar: Stop early in compression test loop (#20142) --- ext/phar/phar_object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 0ad7c5d66d759..ed4ad2516f43b 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -3169,12 +3169,14 @@ static int phar_test_compression(zval *zv, void *argument) /* {{{ */ if (!PHAR_G(has_bz2)) { if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) { *(int *) argument = 0; + return ZEND_HASH_APPLY_STOP; } } if (!PHAR_G(has_zlib)) { if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { *(int *) argument = 0; + return ZEND_HASH_APPLY_STOP; } }