diff --git a/ext/session/session.c b/ext/session/session.c index bf05a547acc..dd57b6ad057 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -2034,15 +2034,13 @@ PHP_FUNCTION(session_set_save_handler) if (register_shutdown) { /* create shutdown function */ php_shutdown_function_entry shutdown_function_entry; - shutdown_function_entry.arg_count = 1; - shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0); - - ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_register_shutdown"); + ZVAL_STRING(&shutdown_function_entry.function_name, "session_register_shutdown"); + shutdown_function_entry.arg_count = 0; + shutdown_function_entry.arguments = NULL; /* add shutdown function, removing the old one if it exists */ if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry)) { - zval_ptr_dtor(&shutdown_function_entry.arguments[0]); - efree(shutdown_function_entry.arguments); + zval_ptr_dtor(&shutdown_function_entry.function_name); php_error_docref(NULL, E_WARNING, "Unable to register session shutdown function"); RETURN_FALSE; } @@ -2665,14 +2663,12 @@ PHP_FUNCTION(session_register_shutdown) * the session still to be available. */ - shutdown_function_entry.arg_count = 1; - shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0); + ZVAL_STRING(&shutdown_function_entry.function_name, "session_write_close"); + shutdown_function_entry.arg_count = 0; + shutdown_function_entry.arguments = NULL; - ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_write_close"); - - if (!append_user_shutdown_function(shutdown_function_entry)) { - zval_ptr_dtor(&shutdown_function_entry.arguments[0]); - efree(shutdown_function_entry.arguments); + if (!append_user_shutdown_function(&shutdown_function_entry)) { + zval_ptr_dtor(&shutdown_function_entry.function_name); /* Unable to register shutdown function, presumably because of lack * of memory, so flush the session now. It would be done in rshutdown diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index d0c8805fe46..8a7d9ca895b 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1658,6 +1658,7 @@ void user_shutdown_function_dtor(zval *zv) /* {{{ */ int i; php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv); + zval_ptr_dtor(&shutdown_function_entry->function_name); for (i = 0; i < shutdown_function_entry->arg_count; i++) { zval_ptr_dtor(&shutdown_function_entry->arguments[i]); } @@ -1682,18 +1683,18 @@ static int user_shutdown_function_call(zval *zv) /* {{{ */ php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv); zval retval; - if (!zend_is_callable(&shutdown_function_entry->arguments[0], 0, NULL)) { - zend_string *function_name = zend_get_callable_name(&shutdown_function_entry->arguments[0]); + if (!zend_is_callable(&shutdown_function_entry->function_name, 0, NULL)) { + zend_string *function_name = zend_get_callable_name(&shutdown_function_entry->function_name); zend_throw_error(NULL, "Registered shutdown function %s() cannot be called, function does not exist", ZSTR_VAL(function_name)); zend_string_release(function_name); return 0; } if (call_user_function(NULL, NULL, - &shutdown_function_entry->arguments[0], + &shutdown_function_entry->function_name, &retval, - shutdown_function_entry->arg_count - 1, - shutdown_function_entry->arguments + 1) == SUCCESS) + shutdown_function_entry->arg_count, + shutdown_function_entry->arguments) == SUCCESS) { zval_ptr_dtor(&retval); } @@ -1787,40 +1788,24 @@ PHPAPI void php_free_shutdown_functions(void) /* {{{ */ /* {{{ Register a user-level function to be called on request termination */ PHP_FUNCTION(register_shutdown_function) { - php_shutdown_function_entry shutdown_function_entry; - int i; + php_shutdown_function_entry entry; + zend_fcall_info fci; + zend_fcall_info_cache fcc; + zval *args; + int arg_count = 0; - shutdown_function_entry.arg_count = ZEND_NUM_ARGS(); - - if (shutdown_function_entry.arg_count < 1) { - WRONG_PARAM_COUNT; - } - - shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), shutdown_function_entry.arg_count, 0); - - if (zend_get_parameters_array(ZEND_NUM_ARGS(), shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { - efree(shutdown_function_entry.arguments); - RETURN_FALSE; - } - - /* Prevent entering of anything but valid callback (syntax check only!) */ - if (!zend_is_callable(&shutdown_function_entry.arguments[0], 0, NULL)) { - zend_string *callback_name = zend_get_callable_name(&shutdown_function_entry.arguments[0]); - zend_argument_type_error(1, "must be a valid callback, function \"%s\" not found or invalid function name", ZSTR_VAL(callback_name)); - efree(shutdown_function_entry.arguments); - zend_string_release(callback_name); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &fci, &fcc, &args, &arg_count) == FAILURE) { RETURN_THROWS(); } - if (!BG(user_shutdown_function_names)) { - ALLOC_HASHTABLE(BG(user_shutdown_function_names)); - zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0); + ZVAL_COPY(&entry.function_name, &fci.function_name); + entry.arguments = (zval *) safe_emalloc(sizeof(zval), arg_count, 0); + entry.arg_count = arg_count; + for (int i = 0; i < arg_count; i++) { + ZVAL_COPY(&entry.arguments[i], &args[i]); } - for (i = 0; i < shutdown_function_entry.arg_count; i++) { - Z_TRY_ADDREF(shutdown_function_entry.arguments[i]); - } - zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry)); + append_user_shutdown_function(&entry); } /* }}} */ @@ -1846,14 +1831,14 @@ PHPAPI zend_bool remove_user_shutdown_function(const char *function_name, size_t } /* }}} */ -PHPAPI zend_bool append_user_shutdown_function(php_shutdown_function_entry shutdown_function_entry) /* {{{ */ +PHPAPI zend_bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry) /* {{{ */ { if (!BG(user_shutdown_function_names)) { ALLOC_HASHTABLE(BG(user_shutdown_function_names)); zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0); } - return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL; + return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL; } /* }}} */ diff --git a/ext/standard/basic_functions.h b/ext/standard/basic_functions.h index 6c0eb5c59ed..97faf50fd92 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -143,13 +143,14 @@ PHPAPI double php_get_nan(void); PHPAPI double php_get_inf(void); typedef struct _php_shutdown_function_entry { + zval function_name; zval *arguments; int arg_count; } php_shutdown_function_entry; PHPAPI extern zend_bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry); PHPAPI extern zend_bool remove_user_shutdown_function(const char *function_name, size_t function_len); -PHPAPI extern zend_bool append_user_shutdown_function(php_shutdown_function_entry shutdown_function_entry); +PHPAPI extern zend_bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry); PHPAPI void php_call_shutdown_functions(void); PHPAPI void php_free_shutdown_functions(void); diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index ec0e056dac9..24aa55cbd7e 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -301,8 +301,7 @@ function forward_static_call(callable $function, mixed ...$args): mixed {} function forward_static_call_array(callable $function, array $args): mixed {} -/** @param callable $function */ -function register_shutdown_function($function, mixed ...$args): ?bool {} +function register_shutdown_function(callable $function, mixed ...$args): ?bool {} function highlight_file(string $filename, bool $return = false): string|bool {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 5e19997bb46..6786cdb04a8 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 97187c073137b8fdfc03bdecf72377ef73d79290 */ + * Stub hash: c373aa965002f4c6a816e6574417ce59473ad7b3 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -456,7 +456,7 @@ ZEND_END_ARG_INFO() #define arginfo_forward_static_call_array arginfo_call_user_func_array ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_register_shutdown_function, 0, 1, _IS_BOOL, 1) - ZEND_ARG_INFO(0, function) + ZEND_ARG_TYPE_INFO(0, function, IS_CALLABLE, 0) ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) ZEND_END_ARG_INFO() diff --git a/ext/standard/tests/general_functions/010.phpt b/ext/standard/tests/general_functions/010.phpt index 31b8bed9050..a8fefd663de 100644 --- a/ext/standard/tests/general_functions/010.phpt +++ b/ext/standard/tests/general_functions/010.phpt @@ -20,5 +20,5 @@ try { echo "Done\n"; ?> --EXPECT-- -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "test::__call" not found or invalid function name +register_shutdown_function(): Argument #1 ($function) must be a valid callback, non-static method test::__call() cannot be called statically Done diff --git a/ext/standard/tests/general_functions/bug32647.phpt b/ext/standard/tests/general_functions/bug32647.phpt index 09735c9d86c..a981a7f4547 100644 --- a/ext/standard/tests/general_functions/bug32647.phpt +++ b/ext/standard/tests/general_functions/bug32647.phpt @@ -73,15 +73,15 @@ register_shutdown_function(array($obj,'barfoo')); ?> --EXPECTF-- Warning: Undefined variable $obj in %s on line %d -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name +register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object Warning: Undefined variable $obj in %s on line %d -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar::foo" not found or invalid function name -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name +register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object +register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object +register_shutdown_function(): Argument #1 ($function) must be a valid callback, class bar does not have a method "foo" +register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar" not found or invalid function name -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar::barfoo" not found or invalid function name -register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar::foobar" not found or invalid function name +register_shutdown_function(): Argument #1 ($function) must be a valid callback, non-static method bar::barfoo() cannot be called statically +register_shutdown_function(): Argument #1 ($function) must be a valid callback, class bar does not have a method "foobar" foo! bar!