From 1805822555e38f6b75eb74be7c8b6856e3eb3d10 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 26 Jul 2026 12:42:35 +0100 Subject: [PATCH 1/2] sapi: only use FCC for header_register_callback() (#22877) No need to rederive callability of zval, or copies of it. --- main/SAPI.c | 54 +++++-------------- main/SAPI.h | 3 +- .../header_register_callback_trampoline.phpt | 16 ++++++ ...allback_trampoline_after_headers_sent.phpt | 17 ++++++ 4 files changed, 48 insertions(+), 42 deletions(-) create mode 100644 tests/basic/header_register_callback_trampoline.phpt create mode 100644 tests/basic/header_register_callback_trampoline_after_headers_sent.phpt diff --git a/main/SAPI.c b/main/SAPI.c index 58e85539d54f..523759ea79be 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -111,51 +111,25 @@ PHP_FUNCTION(header_register_callback) zend_fcall_info fci; zend_fcall_info_cache fcc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fci, &fcc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "F", &fci, &fcc) == FAILURE) { RETURN_THROWS(); } - if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { - zval_ptr_dtor(&SG(callback_func)); - SG(fci_cache) = empty_fcall_info_cache; + if (ZEND_FCC_INITIALIZED(SG(send_header_fcc))) { + zend_fcc_dtor(&SG(send_header_fcc)); } /* Don't store callback if headers have already been sent: * It won't get used and we won't have a chance to release it. */ - if (!SG(headers_sent)) { - ZVAL_COPY(&SG(callback_func), &fci.function_name); + if (UNEXPECTED(SG(headers_sent))) { + zend_release_fcall_info_cache(&fcc); + } else { + zend_fcc_dup(&SG(send_header_fcc), &fcc); } - RETURN_TRUE; } /* }}} */ -static void sapi_run_header_callback(zval *callback) -{ - int error; - zend_fcall_info fci; - char *callback_error = NULL; - zval retval; - - if (zend_fcall_info_init(callback, 0, &fci, &SG(fci_cache), NULL, &callback_error) == SUCCESS) { - fci.retval = &retval; - - error = zend_call_function(&fci, &SG(fci_cache)); - if (error == FAILURE) { - goto callback_failed; - } else { - zval_ptr_dtor(&retval); - } - } else { -callback_failed: - php_error_docref(NULL, E_WARNING, "Could not call the sapi_header_callback"); - } - - if (callback_error) { - efree(callback_error); - } -} - SAPI_API void sapi_handle_post(void *arg) { if (SG(request_info).post_entry && SG(request_info).content_type_dup) { @@ -436,7 +410,6 @@ SAPI_API void sapi_activate(void) SG(sapi_headers).http_status_line = NULL; SG(sapi_headers).mimetype = NULL; SG(headers_sent) = 0; - ZVAL_UNDEF(&SG(callback_func)); SG(read_post_bytes) = 0; SG(request_info).request_body = NULL; SG(request_info).current_user = NULL; @@ -446,6 +419,7 @@ SAPI_API void sapi_activate(void) SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */ SG(global_request_time) = 0; SG(post_read) = 0; + SG(send_header_fcc) = empty_fcall_info_cache; /* It's possible to override this general case in the activate() callback, if necessary. */ if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) { SG(request_info).headers_only = 1; @@ -889,12 +863,12 @@ SAPI_API int sapi_send_headers(void) SG(sapi_headers).send_default_content_type = 0; } - if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { - zval cb; - ZVAL_COPY_VALUE(&cb, &SG(callback_func)); - ZVAL_UNDEF(&SG(callback_func)); - sapi_run_header_callback(&cb); - zval_ptr_dtor(&cb); + if (ZEND_FCC_INITIALIZED(SG(send_header_fcc))) { + zend_fcall_info_cache fcc = SG(send_header_fcc); + /* Prevent triggering the callback multiple times */ + SG(send_header_fcc) = empty_fcall_info_cache; + zend_call_known_fcc(&fcc, NULL, 0, NULL, NULL); + zend_fcc_dtor(&fcc); } SG(headers_sent) = 1; diff --git a/main/SAPI.h b/main/SAPI.h index e62f686603c4..d34c12f1bbc8 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -143,8 +143,7 @@ typedef struct _sapi_globals_struct { bool sapi_started; double global_request_time; HashTable known_post_content_types; - zval callback_func; - zend_fcall_info_cache fci_cache; + zend_fcall_info_cache send_header_fcc; sapi_request_parse_body_context request_parse_body_context; } sapi_globals_struct; diff --git a/tests/basic/header_register_callback_trampoline.phpt b/tests/basic/header_register_callback_trampoline.phpt new file mode 100644 index 000000000000..cc4a1e4014e4 --- /dev/null +++ b/tests/basic/header_register_callback_trampoline.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test header_register_callback +--FILE-- + +--EXPECT-- +Trampoline for trampoline diff --git a/tests/basic/header_register_callback_trampoline_after_headers_sent.phpt b/tests/basic/header_register_callback_trampoline_after_headers_sent.phpt new file mode 100644 index 000000000000..7f343c6d813c --- /dev/null +++ b/tests/basic/header_register_callback_trampoline_after_headers_sent.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test header_register_callback +--FILE-- + +--EXPECT-- +Send headers. From be3477fc66c0e15ba9e21913afd4be7e55a3345e Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 26 Jul 2026 22:09:01 +0800 Subject: [PATCH 2/2] ext/intl: Remove icu-io as a dependency (#22891) This remove the dependency of the ICU IO library in the intl extension. --- NEWS | 1 + build/php.m4 | 4 ++-- ext/intl/config.w32 | 1 - ext/intl/msgformat/msgformat_helpers.cpp | 7 +++---- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index dfcbac915197..91ac10efd3ba 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ PHP NEWS - Intl: . Fixed grammatical issues in Normalizer invalid form and IntlCalendar time zone offset error messages. (Weilin Du) + . Removed the dependency on the ICU IO library. (Weilin Du) - ODBC: . Fixed bug GH-22668 (Heap buffer over-read when a column value exceeds the diff --git a/build/php.m4 b/build/php.m4 index 6d9e3e21387b..d8bf0221e83e 100644 --- a/build/php.m4 +++ b/build/php.m4 @@ -1804,7 +1804,7 @@ dnl dnl Common setup macro for ICU. dnl AC_DEFUN([PHP_SETUP_ICU],[ - PKG_CHECK_MODULES([ICU], [icu-uc >= 57.1 icu-io icu-i18n]) + PKG_CHECK_MODULES([ICU], [icu-uc >= 57.1 icu-i18n]) PHP_EVAL_INCLINE([$ICU_CFLAGS]) PHP_EVAL_LIBLINE([$ICU_LIBS], [$1]) @@ -1812,7 +1812,7 @@ AC_DEFUN([PHP_SETUP_ICU],[ ICU_CFLAGS="$ICU_CFLAGS -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1" ICU_CXXFLAGS="$ICU_CXXFLAGS -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit" - AS_IF([$PKG_CONFIG icu-io --atleast-version=60], + AS_IF([$PKG_CONFIG icu-uc --atleast-version=60], [ICU_CFLAGS="$ICU_CFLAGS -DU_HIDE_OBSOLETE_UTF_OLD_H=1"]) ]) diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index 016f17835f8e..fb30953697b6 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -5,7 +5,6 @@ ARG_ENABLE("intl", "Enable internationalization support", "no"); if (PHP_INTL != "no") { if (CHECK_LIB("icudt.lib", "intl", PHP_INTL) && CHECK_LIB("icuin.lib", "intl", PHP_INTL) && - CHECK_LIB("icuio.lib", "intl", PHP_INTL) && CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && CHECK_HEADER("unicode/utf.h", "CFLAGS_INTL")) { // always build as shared - zend_strtod.c/ICU type conflict diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index e676a07416c2..da18527591d0 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -407,9 +406,9 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, continue; } - UChar temp[16]; - const int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index); - key.append(temp, len); + char temp[16]; + const int32_t len = slprintf(temp, sizeof(temp), "%u", (uint32_t)num_index); + key.append(UnicodeString(temp, len, US_INV)); storedArgType = (Formattable::Type*)zend_hash_index_find_ptr(types, num_index); } else { //string; assumed to be in UTF-8