Skip to content

Commit 8067cf4

Browse files
committed
Use callable type in register_shutdown_function()
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.
1 parent 3d14880 commit 8067cf4

File tree

7 files changed

+42
-61
lines changed

7 files changed

+42
-61
lines changed

ext/session/session.c

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,15 +2034,13 @@ PHP_FUNCTION(session_set_save_handler)
20342034
if (register_shutdown) {
20352035
/* create shutdown function */
20362036
php_shutdown_function_entry shutdown_function_entry;
2037-
shutdown_function_entry.arg_count = 1;
2038-
shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0);
2039-
2040-
ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_register_shutdown");
2037+
ZVAL_STRING(&shutdown_function_entry.function_name, "session_register_shutdown");
2038+
shutdown_function_entry.arg_count = 0;
2039+
shutdown_function_entry.arguments = NULL;
20412040

20422041
/* add shutdown function, removing the old one if it exists */
20432042
if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry)) {
2044-
zval_ptr_dtor(&shutdown_function_entry.arguments[0]);
2045-
efree(shutdown_function_entry.arguments);
2043+
zval_ptr_dtor(&shutdown_function_entry.function_name);
20462044
php_error_docref(NULL, E_WARNING, "Unable to register session shutdown function");
20472045
RETURN_FALSE;
20482046
}
@@ -2665,14 +2663,12 @@ PHP_FUNCTION(session_register_shutdown)
26652663
* the session still to be available.
26662664
*/
26672665

2668-
shutdown_function_entry.arg_count = 1;
2669-
shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0);
2670-
2671-
ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_write_close");
2666+
ZVAL_STRING(&shutdown_function_entry.function_name, "session_write_close");
2667+
shutdown_function_entry.arg_count = 0;
2668+
shutdown_function_entry.arguments = NULL;
26722669

2673-
if (!append_user_shutdown_function(shutdown_function_entry)) {
2674-
zval_ptr_dtor(&shutdown_function_entry.arguments[0]);
2675-
efree(shutdown_function_entry.arguments);
2670+
if (!append_user_shutdown_function(&shutdown_function_entry)) {
2671+
zval_ptr_dtor(&shutdown_function_entry.function_name);
26762672

26772673
/* Unable to register shutdown function, presumably because of lack
26782674
* of memory, so flush the session now. It would be done in rshutdown

ext/standard/basic_functions.c

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,7 @@ void user_shutdown_function_dtor(zval *zv) /* {{{ */
16581658
int i;
16591659
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
16601660

1661+
zval_ptr_dtor(&shutdown_function_entry->function_name);
16611662
for (i = 0; i < shutdown_function_entry->arg_count; i++) {
16621663
zval_ptr_dtor(&shutdown_function_entry->arguments[i]);
16631664
}
@@ -1682,18 +1683,18 @@ static int user_shutdown_function_call(zval *zv) /* {{{ */
16821683
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
16831684
zval retval;
16841685

1685-
if (!zend_is_callable(&shutdown_function_entry->arguments[0], 0, NULL)) {
1686-
zend_string *function_name = zend_get_callable_name(&shutdown_function_entry->arguments[0]);
1686+
if (!zend_is_callable(&shutdown_function_entry->function_name, 0, NULL)) {
1687+
zend_string *function_name = zend_get_callable_name(&shutdown_function_entry->function_name);
16871688
zend_throw_error(NULL, "Registered shutdown function %s() cannot be called, function does not exist", ZSTR_VAL(function_name));
16881689
zend_string_release(function_name);
16891690
return 0;
16901691
}
16911692

16921693
if (call_user_function(NULL, NULL,
1693-
&shutdown_function_entry->arguments[0],
1694+
&shutdown_function_entry->function_name,
16941695
&retval,
1695-
shutdown_function_entry->arg_count - 1,
1696-
shutdown_function_entry->arguments + 1) == SUCCESS)
1696+
shutdown_function_entry->arg_count,
1697+
shutdown_function_entry->arguments) == SUCCESS)
16971698
{
16981699
zval_ptr_dtor(&retval);
16991700
}
@@ -1787,40 +1788,24 @@ PHPAPI void php_free_shutdown_functions(void) /* {{{ */
17871788
/* {{{ Register a user-level function to be called on request termination */
17881789
PHP_FUNCTION(register_shutdown_function)
17891790
{
1790-
php_shutdown_function_entry shutdown_function_entry;
1791-
int i;
1792-
1793-
shutdown_function_entry.arg_count = ZEND_NUM_ARGS();
1794-
1795-
if (shutdown_function_entry.arg_count < 1) {
1796-
WRONG_PARAM_COUNT;
1797-
}
1798-
1799-
shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), shutdown_function_entry.arg_count, 0);
1800-
1801-
if (zend_get_parameters_array(ZEND_NUM_ARGS(), shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) {
1802-
efree(shutdown_function_entry.arguments);
1803-
RETURN_FALSE;
1804-
}
1791+
php_shutdown_function_entry entry;
1792+
zend_fcall_info fci;
1793+
zend_fcall_info_cache fcc;
1794+
zval *args;
1795+
int arg_count = 0;
18051796

1806-
/* Prevent entering of anything but valid callback (syntax check only!) */
1807-
if (!zend_is_callable(&shutdown_function_entry.arguments[0], 0, NULL)) {
1808-
zend_string *callback_name = zend_get_callable_name(&shutdown_function_entry.arguments[0]);
1809-
zend_argument_type_error(1, "must be a valid callback, function \"%s\" not found or invalid function name", ZSTR_VAL(callback_name));
1810-
efree(shutdown_function_entry.arguments);
1811-
zend_string_release(callback_name);
1797+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &fci, &fcc, &args, &arg_count) == FAILURE) {
18121798
RETURN_THROWS();
18131799
}
18141800

1815-
if (!BG(user_shutdown_function_names)) {
1816-
ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1817-
zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1801+
ZVAL_COPY(&entry.function_name, &fci.function_name);
1802+
entry.arguments = (zval *) safe_emalloc(sizeof(zval), arg_count, 0);
1803+
entry.arg_count = arg_count;
1804+
for (int i = 0; i < arg_count; i++) {
1805+
ZVAL_COPY(&entry.arguments[i], &args[i]);
18181806
}
18191807

1820-
for (i = 0; i < shutdown_function_entry.arg_count; i++) {
1821-
Z_TRY_ADDREF(shutdown_function_entry.arguments[i]);
1822-
}
1823-
zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry));
1808+
append_user_shutdown_function(&entry);
18241809
}
18251810
/* }}} */
18261811

@@ -1846,14 +1831,14 @@ PHPAPI zend_bool remove_user_shutdown_function(const char *function_name, size_t
18461831
}
18471832
/* }}} */
18481833

1849-
PHPAPI zend_bool append_user_shutdown_function(php_shutdown_function_entry shutdown_function_entry) /* {{{ */
1834+
PHPAPI zend_bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
18501835
{
18511836
if (!BG(user_shutdown_function_names)) {
18521837
ALLOC_HASHTABLE(BG(user_shutdown_function_names));
18531838
zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
18541839
}
18551840

1856-
return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL;
1841+
return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL;
18571842
}
18581843
/* }}} */
18591844

ext/standard/basic_functions.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,14 @@ PHPAPI double php_get_nan(void);
143143
PHPAPI double php_get_inf(void);
144144

145145
typedef struct _php_shutdown_function_entry {
146+
zval function_name;
146147
zval *arguments;
147148
int arg_count;
148149
} php_shutdown_function_entry;
149150

150151
PHPAPI extern zend_bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry);
151152
PHPAPI extern zend_bool remove_user_shutdown_function(const char *function_name, size_t function_len);
152-
PHPAPI extern zend_bool append_user_shutdown_function(php_shutdown_function_entry shutdown_function_entry);
153+
PHPAPI extern zend_bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry);
153154

154155
PHPAPI void php_call_shutdown_functions(void);
155156
PHPAPI void php_free_shutdown_functions(void);

ext/standard/basic_functions.stub.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,7 @@ function forward_static_call(callable $function, mixed ...$args): mixed {}
301301

302302
function forward_static_call_array(callable $function, array $args): mixed {}
303303

304-
/** @param callable $function */
305-
function register_shutdown_function($function, mixed ...$args): ?bool {}
304+
function register_shutdown_function(callable $function, mixed ...$args): ?bool {}
306305

307306
function highlight_file(string $filename, bool $return = false): string|bool {}
308307

ext/standard/basic_functions_arginfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 97187c073137b8fdfc03bdecf72377ef73d79290 */
2+
* Stub hash: c373aa965002f4c6a816e6574417ce59473ad7b3 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
55
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
@@ -456,7 +456,7 @@ ZEND_END_ARG_INFO()
456456
#define arginfo_forward_static_call_array arginfo_call_user_func_array
457457

458458
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_register_shutdown_function, 0, 1, _IS_BOOL, 1)
459-
ZEND_ARG_INFO(0, function)
459+
ZEND_ARG_TYPE_INFO(0, function, IS_CALLABLE, 0)
460460
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
461461
ZEND_END_ARG_INFO()
462462

ext/standard/tests/general_functions/010.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ try {
2020
echo "Done\n";
2121
?>
2222
--EXPECT--
23-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "test::__call" not found or invalid function name
23+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, non-static method test::__call() cannot be called statically
2424
Done

ext/standard/tests/general_functions/bug32647.phpt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ register_shutdown_function(array($obj,'barfoo'));
7373
?>
7474
--EXPECTF--
7575
Warning: Undefined variable $obj in %s on line %d
76-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name
76+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
7777

7878
Warning: Undefined variable $obj in %s on line %d
79-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name
80-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name
81-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar::foo" not found or invalid function name
82-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "Array" not found or invalid function name
79+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
80+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
81+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, class bar does not have a method "foo"
82+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
8383
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar" not found or invalid function name
84-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar::barfoo" not found or invalid function name
85-
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function "bar::foobar" not found or invalid function name
84+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, non-static method bar::barfoo() cannot be called statically
85+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, class bar does not have a method "foobar"
8686
foo!
8787
bar!

0 commit comments

Comments
 (0)