From 0cdd3c32def0e1ccfe5300d5a7d59688596938b3 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 29 May 2025 19:09:11 +0100 Subject: [PATCH 1/6] ext/pgsql: Stop using useless convert_to_boolean() API (#18683) There are better ways of handling this than casting the zval in place --- ext/pgsql/pgsql.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index f10bfd6dcbbf6..ba6d660d0307e 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -3879,7 +3879,12 @@ static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) switch(entry_type) { case PHP_PG_ASYNC_IS_BUSY: PQconsumeInput(pgsql); - RETVAL_LONG(PQisBusy(pgsql)); + /* PQisBusy + * Returns 1 if a command is busy, that is, PQgetResult would block waiting for input. + * A 0 return indicates that PQgetResult can be called with assurance of not blocking. + * https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQISBUSY + */ + RETVAL_BOOL(PQisBusy(pgsql)); break; case PHP_PG_ASYNC_REQUEST_CANCEL: { PGcancel *c; @@ -3893,7 +3898,8 @@ static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) * errbuf must be a char array of size errbufsize (the recommended size is 256 bytes). * https://www.postgresql.org/docs/current/libpq-cancel.html#LIBPQ-PQCANCEL */ - RETVAL_LONG((rc = PQcancel(c, err, sizeof(err)))); + rc = PQcancel(c, err, sizeof(err)); + RETVAL_BOOL(rc); if (rc == 0) { zend_error(E_WARNING, "cannot cancel the query: %s", err); } @@ -3908,7 +3914,6 @@ static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) if (PQsetnonblocking(pgsql, 0)) { php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode"); } - convert_to_boolean(return_value); } /* }}} */ @@ -4929,8 +4934,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string * break; /* break out for() */ } - convert_to_boolean(is_enum); - if (Z_TYPE_P(is_enum) == IS_TRUE) { + if (zval_is_true(is_enum)) { /* enums need to be treated like strings */ data_type = PG_TEXT; } else { From f0fa9c748a774ba9c8359fa9d97fde1f63976800 Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Thu, 29 May 2025 11:11:00 -0700 Subject: [PATCH 2/6] zend_ast.c: use `smart_str_appendc` for appending single characters (#18703) Slightly more performant --- Zend/zend_ast.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 5104aad3510e0..26a0cbd16ca51 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1871,7 +1871,7 @@ static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_d smart_str_appends(str, " {\n"); zend_ast_export_stmt(str, decl->child[2], indent + 1); zend_ast_export_indent(str, indent); - smart_str_appends(str, "}"); + smart_str_appendc(str, '}'); } static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) { @@ -1899,7 +1899,7 @@ static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, for (i = 0; i < list->children; i++) { smart_str_appends(str, "#["); zend_ast_export_attribute_group(str, list->child[i], indent); - smart_str_appends(str, "]"); + smart_str_appendc(str, ']'); if (newlines) { smart_str_appendc(str, '\n'); @@ -2060,7 +2060,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio case ZEND_AST_OP_ARRAY: smart_str_appends(str, "Closure("); smart_str_append(str, zend_ast_get_op_array(ast)->op_array->function_name); - smart_str_appends(str, ")"); + smart_str_appendc(str, ')'); break; case ZEND_AST_CONSTANT_CLASS: smart_str_appendl(str, "__CLASS__", sizeof("__CLASS__")-1); @@ -2427,9 +2427,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio case ZEND_AST_CALL: { zend_ast *left = ast->child[0]; if (left->kind == ZEND_AST_ARROW_FUNC || left->kind == ZEND_AST_CLOSURE) { - smart_str_appends(str, "("); + smart_str_appendc(str, '('); zend_ast_export_ns_name(str, left, 0, indent); - smart_str_appends(str, ")"); + smart_str_appendc(str, ')'); } else { zend_ast_export_ns_name(str, left, 0, indent); } @@ -2679,9 +2679,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio smart_str_appends(str, " {\n"); zend_ast_export_ex(str, ast->child[1], 0, indent + 1); zend_ast_export_indent(str, indent); - smart_str_appends(str, "}"); + smart_str_appendc(str, '}'); } else { - smart_str_appends(str, ";"); + smart_str_appendc(str, ';'); } break; case ZEND_AST_TRAIT_PRECEDENCE: From 615b9803bb0d47894b38b2848e895da47443b67f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 29 May 2025 20:14:57 +0200 Subject: [PATCH 3/6] Get rid of redundant SOAP globals (#18702) The copy doesn't make sense, remove it. --- ext/soap/php_encoding.c | 4 ++-- ext/soap/php_sdl.c | 2 +- ext/soap/php_soap.h | 5 ++--- ext/soap/soap.c | 39 +++++++++++++++++++-------------------- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index c4fa7702cf446..e3bd3029388b6 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -3456,7 +3456,7 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns) if (xmlns == NULL) { xmlChar* prefix; - if ((prefix = zend_hash_str_find_ptr(&SOAP_GLOBAL(defEncNs), (char*)ns, strlen(ns))) != NULL) { + if ((prefix = zend_hash_str_find_ptr(&php_soap_defEncNs, (char*)ns, strlen(ns))) != NULL) { xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), prefix); } else { smart_str prefix = {0}; @@ -3531,7 +3531,7 @@ encodePtr get_conversion(int encode) { encodePtr enc; - if ((enc = zend_hash_index_find_ptr(&SOAP_GLOBAL(defEncIndex), encode)) == NULL) { + if ((enc = zend_hash_index_find_ptr(&php_soap_defEncIndex, encode)) == NULL) { soap_error0(E_ERROR, "Encoding: Cannot find encoding"); return NULL; } else { diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 5826c82c644ed..9a9df79482739 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -177,7 +177,7 @@ encodePtr get_encoder_ex(sdlPtr sdl, const char *nscat, size_t len) { encodePtr enc; - if ((enc = zend_hash_str_find_ptr(&SOAP_GLOBAL(defEnc), nscat, len)) != NULL) { + if ((enc = zend_hash_str_find_ptr(&php_soap_defEnc, nscat, len)) != NULL) { return enc; } else if (sdl && sdl->encoders && (enc = zend_hash_str_find_ptr(sdl->encoders, nscat, len)) != NULL) { return enc; diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index a78734aa7f17a..89dbf4408be2f 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -151,9 +151,6 @@ struct _soapService { ZEND_BEGIN_MODULE_GLOBALS(soap) - HashTable defEncNs; /* mapping of default namespaces to prefixes */ - HashTable defEnc; - HashTable defEncIndex; HashTable *typemap; int cur_uniq_ns; int soap_version; @@ -195,6 +192,8 @@ extern zend_class_entry* soap_var_class_entry; extern zend_class_entry* soap_url_class_entry; extern zend_class_entry* soap_sdl_class_entry; +extern HashTable php_soap_defEncNs, php_soap_defEnc, php_soap_defEncIndex; + void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); #define soap_error0(severity, format) \ diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 09043886b9c63..094730b88f412 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -390,16 +390,18 @@ STD_PHP_INI_ENTRY("soap.wsdl_cache_limit", "5", PHP_INI_ALL, OnUpdateLong, cache_limit, zend_soap_globals, soap_globals) PHP_INI_END() -static HashTable defEnc, defEncIndex, defEncNs; +/* Real globals shared for the entire processes across threads, only written during init. */ +HashTable php_soap_defEncNs; /* mapping of default namespaces to prefixes */ +HashTable php_soap_defEnc, php_soap_defEncIndex; static void php_soap_prepare_globals(void) { int i; encode* enc; - zend_hash_init(&defEnc, 0, NULL, NULL, 1); - zend_hash_init(&defEncIndex, 0, NULL, NULL, 1); - zend_hash_init(&defEncNs, 0, NULL, NULL, 1); + zend_hash_init(&php_soap_defEnc, 0, NULL, NULL, 1); + zend_hash_init(&php_soap_defEncIndex, 0, NULL, NULL, 1); + zend_hash_init(&php_soap_defEncNs, 0, NULL, NULL, 1); i = 0; do { @@ -412,25 +414,25 @@ static void php_soap_prepare_globals(void) size_t clark_notation_len = spprintf(&clark_notation, 0, "{%s}%s", enc->details.ns, enc->details.type_str); enc->details.clark_notation = zend_string_init(clark_notation, clark_notation_len, true); size_t ns_type_len = spprintf(&ns_type, 0, "%s:%s", enc->details.ns, enc->details.type_str); - zend_hash_str_add_ptr(&defEnc, ns_type, ns_type_len, (void*)enc); + zend_hash_str_add_ptr(&php_soap_defEnc, ns_type, ns_type_len, (void*)enc); efree(clark_notation); efree(ns_type); } else { - zend_hash_str_add_ptr(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc); + zend_hash_str_add_ptr(&php_soap_defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc); } } /* Index everything by number */ - zend_hash_index_add_ptr(&defEncIndex, defaultEncoding[i].details.type, (void*)enc); + zend_hash_index_add_ptr(&php_soap_defEncIndex, defaultEncoding[i].details.type, (void*)enc); i++; } while (defaultEncoding[i].details.type != END_KNOWN_TYPES); /* hash by namespace */ - zend_hash_str_add_ptr(&defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE)-1, XSD_NS_PREFIX); - zend_hash_str_add_ptr(&defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1, XSD_NS_PREFIX); - zend_hash_str_add_ptr(&defEncNs, XSI_NAMESPACE, sizeof(XSI_NAMESPACE)-1, XSI_NS_PREFIX); - zend_hash_str_add_ptr(&defEncNs, XML_NAMESPACE, sizeof(XML_NAMESPACE)-1, XML_NS_PREFIX); - zend_hash_str_add_ptr(&defEncNs, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1, SOAP_1_1_ENC_NS_PREFIX); - zend_hash_str_add_ptr(&defEncNs, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1, SOAP_1_2_ENC_NS_PREFIX); + zend_hash_str_add_ptr(&php_soap_defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE)-1, XSD_NS_PREFIX); + zend_hash_str_add_ptr(&php_soap_defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1, XSD_NS_PREFIX); + zend_hash_str_add_ptr(&php_soap_defEncNs, XSI_NAMESPACE, sizeof(XSI_NAMESPACE)-1, XSI_NS_PREFIX); + zend_hash_str_add_ptr(&php_soap_defEncNs, XML_NAMESPACE, sizeof(XML_NAMESPACE)-1, XML_NS_PREFIX); + zend_hash_str_add_ptr(&php_soap_defEncNs, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1, SOAP_1_1_ENC_NS_PREFIX); + zend_hash_str_add_ptr(&php_soap_defEncNs, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1, SOAP_1_2_ENC_NS_PREFIX); } static void php_soap_init_globals(zend_soap_globals *soap_globals) @@ -438,9 +440,6 @@ static void php_soap_init_globals(zend_soap_globals *soap_globals) #if defined(COMPILE_DL_SOAP) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif - soap_globals->defEnc = defEnc; - soap_globals->defEncIndex = defEncIndex; - soap_globals->defEncNs = defEncNs; soap_globals->typemap = NULL; soap_globals->use_soap_error_handler = 0; soap_globals->error_code = NULL; @@ -461,9 +460,9 @@ PHP_MSHUTDOWN_FUNCTION(soap) i++; } while (defaultEncoding[i].details.type != END_KNOWN_TYPES); zend_error_cb = old_error_handler; - zend_hash_destroy(&SOAP_GLOBAL(defEnc)); - zend_hash_destroy(&SOAP_GLOBAL(defEncIndex)); - zend_hash_destroy(&SOAP_GLOBAL(defEncNs)); + zend_hash_destroy(&php_soap_defEnc); + zend_hash_destroy(&php_soap_defEncIndex); + zend_hash_destroy(&php_soap_defEncNs); if (SOAP_GLOBAL(mem_cache)) { zend_hash_destroy(SOAP_GLOBAL(mem_cache)); free(SOAP_GLOBAL(mem_cache)); @@ -765,7 +764,7 @@ PHP_METHOD(SoapVar, __construct) if (type_is_null) { ZVAL_LONG(Z_VAR_ENC_TYPE_P(this_ptr), UNKNOWN_TYPE); } else { - if (zend_hash_index_exists(&SOAP_GLOBAL(defEncIndex), type)) { + if (zend_hash_index_exists(&php_soap_defEncIndex, type)) { ZVAL_LONG(Z_VAR_ENC_TYPE_P(this_ptr), type); } else { zend_argument_value_error(2, "is not a valid encoding"); From 087f38f3476b2f6c73cf2567ccbe19636c2c975d Mon Sep 17 00:00:00 2001 From: Oleg Efimov Date: Thu, 29 May 2025 21:46:11 +0100 Subject: [PATCH 4/6] Fix GH-18695: float numbers zero fraction is now preserved in zend_ast_export() (#18699) --- NEWS | 4 ++++ Zend/tests/ast/ast_serialize_floats.phpt | 26 ++++++++++++++++++++++++ Zend/zend_ast.c | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/ast/ast_serialize_floats.phpt diff --git a/NEWS b/NEWS index 466ba5d89653e..379718ba2a9ba 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.23 +- Core: + . Fixed GH-18695 (zend_ast_export() - float number is not preserved). + (Oleg Efimov) + - Date: . Fix leaks with multiple calls to DatePeriod iterator current(). (nielsdos) diff --git a/Zend/tests/ast/ast_serialize_floats.phpt b/Zend/tests/ast/ast_serialize_floats.phpt new file mode 100644 index 0000000000000..164b8b03338cf --- /dev/null +++ b/Zend/tests/ast/ast_serialize_floats.phpt @@ -0,0 +1,26 @@ +--TEST-- +Serialization of floats are correct +--INI-- +zend.assertions=1 +--FILE-- +getMessage(), ' failed', PHP_EOL; +} +try { + assert(!is_float(1.1)); +} catch (AssertionError $e) { + echo 'assert(): ', $e->getMessage(), ' failed', PHP_EOL; +} +try { + assert(!is_float(1234.5678)); +} catch (AssertionError $e) { + echo 'assert(): ', $e->getMessage(), ' failed', PHP_EOL; +} +?> +--EXPECT-- +assert(): assert(!is_float(0.0)) failed +assert(): assert(!is_float(1.1)) failed +assert(): assert(!is_float(1234.5678)) failed diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 0fb50e2eae1f5..f8c4ca17a9b95 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1563,7 +1563,7 @@ static ZEND_COLD void zend_ast_export_zval(smart_str *str, zval *zv, int priorit break; case IS_DOUBLE: smart_str_append_double( - str, Z_DVAL_P(zv), (int) EG(precision), /* zero_fraction */ false); + str, Z_DVAL_P(zv), (int) EG(precision), /* zero_fraction */ true); break; case IS_STRING: smart_str_appendc(str, '\''); From 90a9fb59ceef95254da74587a7c3520660a6e700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 29 May 2025 23:40:13 +0200 Subject: [PATCH 5/6] [skip ci] Remove NEWS for non-master change see 6b95875dc5077428936da90ac85328de2dbf3382 --- NEWS | 2 -- 1 file changed, 2 deletions(-) diff --git a/NEWS b/NEWS index 2ae38ccd45923..6dffb0cc847a0 100644 --- a/NEWS +++ b/NEWS @@ -53,8 +53,6 @@ PHP NEWS evaluation) and GH-18464 (Recursion protection for deprecation constants not released on bailout). (DanielEScherzer and ilutov) . Fixed AST printing for immediately invoked Closure. (Dmitrii Derepko) - . Fixed GH-18695 (zend_ast_export() - float number is not preserved). - (Oleg Efimov) - Curl: . Added curl_multi_get_handles(). (timwolla) From 56abb316eb9981372c06b0bf339cc035293316a4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 29 May 2025 22:13:43 +0200 Subject: [PATCH 6/6] Fix bug #70951: Segmentation fault on invalid WSDL cache We mix in the endianness and the zend_long size to make sure cache files can't be used on incompatible architectures. Closes GH-18707. --- NEWS | 1 + ext/soap/php_sdl.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/NEWS b/NEWS index 6dffb0cc847a0..baf838481682c 100644 --- a/NEWS +++ b/NEWS @@ -186,6 +186,7 @@ PHP NEWS header is correct). (nielsdos) . Fix namespace handling of WSDL and XML schema in SOAP, fixing at least GH-16320 and bug #68576. (nielsdos) + . Fixed bug #70951 (Segmentation fault on invalid WSDL cache). (nielsdos) - Sockets: . Added IPPROTO_ICMP/IPPROTO_ICMPV6 to create raw socket for ICMP usage. diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 9a9df79482739..cc01b598bd9c3 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -31,6 +31,12 @@ # define O_BINARY 0 #endif +#ifdef WORDS_BIGENDIAN +# define SOAP_BIG_ENDIAN 1 +#else +# define SOAP_BIG_ENDIAN 0 +#endif + static void delete_fault(zval *zv); static void delete_fault_persistent(zval *zv); static void delete_binding(zval *zv); @@ -3188,9 +3194,13 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl) char *user = php_get_current_user(); size_t user_len = user ? strlen(user) + 1 : 0; + /* System architecture identification (see bug #70951) */ + static const char ids[] = {SIZEOF_ZEND_LONG, SOAP_BIG_ENDIAN}; + md5str[0] = '\0'; PHP_MD5Init(&md5_context); PHP_MD5Update(&md5_context, (unsigned char*)uri, uri_len); + PHP_MD5Update(&md5_context, ids, sizeof(ids)); PHP_MD5Final(digest, &md5_context); make_digest(md5str, digest); key = emalloc(len+sizeof("/wsdl-")-1+user_len+2+sizeof(md5str));