]> granicus.if.org Git - php/commitdiff
Use callable type in register_shutdown_function()
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 25 Sep 2020 12:47:10 +0000 (14:47 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 25 Sep 2020 12:48:33 +0000 (14:48 +0200)
To make things a bit less weird, split off the function name into
a zval stored separately from the arguments. This allows us to
use normal zpp and get standard behavior.

ext/session/session.c
ext/standard/basic_functions.c
ext/standard/basic_functions.h
ext/standard/basic_functions.stub.php
ext/standard/basic_functions_arginfo.h
ext/standard/tests/general_functions/010.phpt
ext/standard/tests/general_functions/bug32647.phpt

index bf05a547acc3587db233fa302b19b3c533aeb95e..dd57b6ad0575f30231148568ff56bfee38f575cb 100644 (file)
@@ -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.arguments[0], "session_write_close");
+       ZVAL_STRING(&shutdown_function_entry.function_name, "session_write_close");
+       shutdown_function_entry.arg_count = 0;
+       shutdown_function_entry.arguments = NULL;
 
-       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
index d0c8805fe461a8ca7ab77fa935cbf893305b7788..8a7d9ca895bfb7ac25e195b8e36fbb5d2ce0e773 100755 (executable)
@@ -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;
-
-       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;
-       }
+       php_shutdown_function_entry entry;
+       zend_fcall_info fci;
+       zend_fcall_info_cache fcc;
+       zval *args;
+       int arg_count = 0;
 
-       /* 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;
 }
 /* }}} */
 
index 6c0eb5c59edc0fbcdd29a83ca2c0bde3c3d90a2c..97faf50fd92e9de6fc8b139a4cadc925e3843275 100644 (file)
@@ -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);
index ec0e056dac9a00927b4f3f3911ef4256ea1528e8..24aa55cbd7e0595c9897b11c47f430815185975c 100755 (executable)
@@ -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 {}
 
index 5e19997bb46487dc0cbda9b3670100c629cef5d1..6786cdb04a862502f8e6f1269592f8ee81204b4d 100644 (file)
@@ -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()
 
index 31b8bed9050c2dab7da32a1d4cb4ffad47ca0bb7..a8fefd663debd995df76b139b0cce0d6756426a5 100644 (file)
@@ -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
index 09735c9d86c48a249c8e4876c4e25d3ad32d1f39..a981a7f454781f8b3eaab2f9e5eb7bbe276d3005 100644 (file)
@@ -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!