Commit 9be36f0cd47 for php.net
commit 9be36f0cd474d7d66b4f42935af26fd514a8b5ac
Author: Gina Peter Banyard <girgias@php.net>
Date: Fri Jul 31 10:37:19 2026 +0100
output: only use FCC for storing user output handler (#22815)
diff --git a/main/output.c b/main/output.c
index 664adf7f168..8221425f5cf 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_ex(handler->func.user_fcc, &retval, 2, ob_args, NULL, zend_fci_consumed_arg(0));
- 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
@@ -1026,9 +1025,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
status = PHP_OUTPUT_HANDLER_FAILURE;
}
- /* Free arguments and return value */
- zval_ptr_dtor(&ob_args[0]);
- zval_ptr_dtor(&ob_args[1]);
+ /* Free return value */
zval_ptr_dtor(&retval);
} else {
diff --git a/main/php_output.h b/main/php_output.h
index f0a26824936..4db6809d493 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;