From 00621f123528c358cea88d0004a27c5c6e6e6dae Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 23:15:13 +0100 Subject: [PATCH] output: only use FCC for storing user output handler --- main/output.c | 35 ++++++++++++++++------------------- main/php_output.h | 8 +------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/main/output.c b/main/output.c index 664adf7f1688..b8d3b6c04d7e 100644 --- a/main/output.c +++ b/main/output.c @@ -468,7 +468,6 @@ PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, char *error = NULL; php_output_handler *handler = NULL; php_output_handler_alias_ctor_t alias = NULL; - php_output_handler_user_func_t *user = NULL; switch (Z_TYPE_P(output_handler)) { case IS_NULL: @@ -480,22 +479,23 @@ PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, break; } ZEND_FALLTHROUGH; - default: - user = ecalloc(1, sizeof(php_output_handler_user_func_t)); - if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, &handler_name, &error)) { + default: { + zend_fcall_info_cache *fcc = ecalloc(1, sizeof(*fcc)); + + if (zend_is_callable_ex(output_handler, NULL, 0, &handler_name, fcc, &error)) { handler = php_output_handler_init(handler_name, chunk_size, PHP_OUTPUT_HANDLER_ABILITY_FLAGS(flags) | PHP_OUTPUT_HANDLER_USER); - ZVAL_COPY(&user->zoh, output_handler); - handler->func.user = user; + zend_fcc_addref(fcc); + handler->func.user_fcc = fcc; } else { - efree(user); - } - if (error) { + efree(fcc); + ZEND_ASSERT(error); php_error_docref("ref.outcontrol", E_WARNING, "%s", error); efree(error); } if (handler_name) { zend_string_release_ex(handler_name, 0); } + } } return handler; @@ -707,8 +707,8 @@ PHPAPI void php_output_handler_dtor(php_output_handler *handler) efree(handler->buffer.data); } if (handler->flags & PHP_OUTPUT_HANDLER_USER) { - zval_ptr_dtor(&handler->func.user->zoh); - efree(handler->func.user); + zend_fcc_dtor(handler->func.user_fcc); + efree(handler->func.user_fcc); } if (handler->dtor && handler->opaq) { handler->dtor(handler->opaq); @@ -966,13 +966,12 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl /* ob_mode */ ZVAL_LONG(&ob_args[1], (zend_long) context->op); - /* Set FCI info */ - handler->func.user->fci.param_count = 2; - handler->func.user->fci.params = ob_args; - handler->func.user->fci.retval = &retval; - handler->func.user->fci.consumed_args = zend_fci_consumed_arg(0); + zend_call_known_fcc(handler->func.user_fcc, &retval, 2, ob_args, NULL); - if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) { + zval_ptr_dtor(&ob_args[0]); + zval_ptr_dtor(&ob_args[1]); + + if (Z_TYPE(retval) != IS_UNDEF) { if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { // Make sure that we don't get lost in the current output buffer // by disabling it @@ -1027,8 +1026,6 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl } /* Free arguments and return value */ - zval_ptr_dtor(&ob_args[0]); - zval_ptr_dtor(&ob_args[1]); zval_ptr_dtor(&retval); } else { diff --git a/main/php_output.h b/main/php_output.h index f0a26824936a..4db6809d4936 100644 --- a/main/php_output.h +++ b/main/php_output.h @@ -112,12 +112,6 @@ typedef zend_result (*php_output_handler_conflict_check_t)(const char *handler_n /* ctor for aliases */ typedef struct _php_output_handler *(*php_output_handler_alias_ctor_t)(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags); -typedef struct _php_output_handler_user_func_t { - zend_fcall_info fci; - zend_fcall_info_cache fcc; - zval zoh; -} php_output_handler_user_func_t; - typedef struct _php_output_handler { zend_string *name; int flags; @@ -129,7 +123,7 @@ typedef struct _php_output_handler { void (*dtor)(void *opaq); union { - php_output_handler_user_func_t *user; + zend_fcall_info_cache *user_fcc; php_output_handler_context_func_t internal; } func; } php_output_handler;