Skip to content

Commit 728d666

Browse files
committed
Refactor register shutdown function mechanism
1 parent af1de14 commit 728d666

File tree

7 files changed

+90
-100
lines changed

7 files changed

+90
-100
lines changed

ext/session/session.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,18 +2012,13 @@ PHP_FUNCTION(session_set_save_handler)
20122012
if (register_shutdown) {
20132013
/* create shutdown function */
20142014
php_shutdown_function_entry shutdown_function_entry;
2015-
shutdown_function_entry.arg_count = 1;
2016-
shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0);
2015+
zval callable;
20172016

2018-
ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_register_shutdown");
2017+
ZVAL_STRING(&callable, "session_write_close");
2018+
zend_fcall_info_init(&callable, 0, &shutdown_function_entry.fci, &shutdown_function_entry.fci_cache, NULL, NULL);
20192019

20202020
/* add shutdown function, removing the old one if it exists */
2021-
if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry)) {
2022-
zval_ptr_dtor(&shutdown_function_entry.arguments[0]);
2023-
efree(shutdown_function_entry.arguments);
2024-
php_error_docref(NULL, E_WARNING, "Unable to register session shutdown function");
2025-
RETURN_FALSE;
2026-
}
2021+
register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry);
20272022
} else {
20282023
/* remove shutdown function */
20292024
remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1);
@@ -2621,6 +2616,7 @@ PHP_FUNCTION(session_status)
26212616
PHP_FUNCTION(session_register_shutdown)
26222617
{
26232618
php_shutdown_function_entry shutdown_function_entry;
2619+
zval callable;
26242620

26252621
ZEND_PARSE_PARAMETERS_NONE();
26262622

@@ -2630,15 +2626,12 @@ PHP_FUNCTION(session_register_shutdown)
26302626
* function after calling session_set_save_handler(), which expects
26312627
* the session still to be available.
26322628
*/
2633-
2634-
shutdown_function_entry.arg_count = 1;
2635-
shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0);
2636-
2637-
ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_write_close");
2629+
ZVAL_STRING(&callable, "session_write_close");
2630+
zend_fcall_info_init(&callable, 0, &shutdown_function_entry.fci, &shutdown_function_entry.fci_cache, NULL, NULL);
26382631

26392632
if (!append_user_shutdown_function(shutdown_function_entry)) {
2640-
zval_ptr_dtor(&shutdown_function_entry.arguments[0]);
2641-
efree(shutdown_function_entry.arguments);
2633+
zval_ptr_dtor(&shutdown_function_entry.fci.function_name);
2634+
//efree(shutdown_function_entry);
26422635

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

ext/standard/basic_functions.c

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,13 +1660,10 @@ PHP_FUNCTION(forward_static_call_array)
16601660

16611661
void user_shutdown_function_dtor(zval *zv) /* {{{ */
16621662
{
1663-
int i;
16641663
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
16651664

1666-
for (i = 0; i < shutdown_function_entry->arg_count; i++) {
1667-
zval_ptr_dtor(&shutdown_function_entry->arguments[i]);
1668-
}
1669-
efree(shutdown_function_entry->arguments);
1665+
zval_ptr_dtor(&shutdown_function_entry->fci.function_name);
1666+
16701667
efree(shutdown_function_entry);
16711668
}
16721669
/* }}} */
@@ -1687,22 +1684,13 @@ static int user_shutdown_function_call(zval *zv) /* {{{ */
16871684
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
16881685
zval retval;
16891686

1690-
if (!zend_is_callable(&shutdown_function_entry->arguments[0], 0, NULL)) {
1691-
zend_string *function_name
1692-
= zend_get_callable_name(&shutdown_function_entry->arguments[0]);
1693-
php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", ZSTR_VAL(function_name));
1694-
zend_string_release_ex(function_name, 0);
1695-
return 0;
1696-
}
1687+
shutdown_function_entry->fci.retval = &retval;
16971688

1698-
if (call_user_function(NULL, NULL,
1699-
&shutdown_function_entry->arguments[0],
1700-
&retval,
1701-
shutdown_function_entry->arg_count - 1,
1702-
shutdown_function_entry->arguments + 1) == SUCCESS)
1703-
{
1704-
zval_ptr_dtor(&retval);
1689+
if (zend_call_function(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache) == SUCCESS) {
1690+
zval_ptr_dtor(shutdown_function_entry->fci.retval);
17051691
}
1692+
1693+
zend_release_fcall_info_cache(&shutdown_function_entry->fci_cache);
17061694
return 0;
17071695
}
17081696
/* }}} */
@@ -1805,40 +1793,20 @@ PHPAPI void php_free_shutdown_functions(void) /* {{{ */
18051793
PHP_FUNCTION(register_shutdown_function)
18061794
{
18071795
php_shutdown_function_entry shutdown_function_entry;
1808-
int i;
1809-
1810-
shutdown_function_entry.arg_count = ZEND_NUM_ARGS();
1811-
1812-
if (shutdown_function_entry.arg_count < 1) {
1813-
WRONG_PARAM_COUNT;
1814-
}
18151796

1816-
shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), shutdown_function_entry.arg_count, 0);
1797+
ZEND_PARSE_PARAMETERS_START(1, -1)
1798+
Z_PARAM_FUNC(shutdown_function_entry.fci, shutdown_function_entry.fci_cache)
1799+
Z_PARAM_VARIADIC('*', shutdown_function_entry.fci.params, shutdown_function_entry.fci.param_count)
1800+
ZEND_PARSE_PARAMETERS_END();
18171801

1818-
if (zend_get_parameters_array(ZEND_NUM_ARGS(), shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) {
1819-
efree(shutdown_function_entry.arguments);
1820-
RETURN_FALSE;
1821-
}
1802+
Z_TRY_ADDREF(shutdown_function_entry.fci.function_name);
18221803

1823-
/* Prevent entering of anything but valid callback (syntax check only!) */
1824-
if (!zend_is_callable(&shutdown_function_entry.arguments[0], 0, NULL)) {
1825-
zend_string *callback_name
1826-
= zend_get_callable_name(&shutdown_function_entry.arguments[0]);
1827-
php_error_docref(NULL, E_WARNING, "Invalid shutdown callback '%s' passed", ZSTR_VAL(callback_name));
1828-
efree(shutdown_function_entry.arguments);
1829-
zend_string_release_ex(callback_name, 0);
1830-
RETVAL_FALSE;
1831-
} else {
1832-
if (!BG(user_shutdown_function_names)) {
1833-
ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1834-
zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1835-
}
18361804

1837-
for (i = 0; i < shutdown_function_entry.arg_count; i++) {
1838-
Z_TRY_ADDREF(shutdown_function_entry.arguments[i]);
1839-
}
1840-
zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry));
1805+
if (!BG(user_shutdown_function_names)) {
1806+
ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1807+
zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
18411808
}
1809+
zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry));
18421810
}
18431811
/* }}} */
18441812

ext/standard/basic_functions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ PHPAPI double php_get_nan(void);
146146
PHPAPI double php_get_inf(void);
147147

148148
typedef struct _php_shutdown_function_entry {
149-
zval *arguments;
150-
int arg_count;
149+
zend_fcall_info fci;
150+
zend_fcall_info_cache fci_cache;
151151
} php_shutdown_function_entry;
152152

153153
PHPAPI extern zend_bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry);

ext/standard/basic_functions.stub.php

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

294294
function forward_static_call_array(callable $function, array $args): mixed {}
295295

296-
/** @param callable $function */
297-
function register_shutdown_function($function, mixed ...$args): ?bool {}
296+
function register_shutdown_function(callable $function, mixed ...$args): ?bool {}
298297

299298
function highlight_file(string $filename, bool $return = false): string|bool|null {}
300299

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: 05b740207a70a9d272b4c327882fd0b52016a0af */
2+
* Stub hash: b2264d2c27917c93f88ac3ad1a98d81a3726233a */
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)
@@ -463,7 +463,7 @@ ZEND_END_ARG_INFO()
463463
#define arginfo_forward_static_call_array arginfo_call_user_func_array
464464

465465
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_register_shutdown_function, 0, 1, _IS_BOOL, 1)
466-
ZEND_ARG_INFO(0, function)
466+
ZEND_ARG_TYPE_INFO(0, function, IS_CALLABLE, 0)
467467
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
468468
ZEND_END_ARG_INFO()
469469

ext/standard/tests/general_functions/010.phpt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ class test {
1111
}
1212
}
1313

14-
var_dump(register_shutdown_function(array("test","__call")));
14+
try {
15+
var_dump(register_shutdown_function(array("test","__call")));
16+
} catch (\TypeError $e) {
17+
echo $e->getMessage() . \PHP_EOL;
18+
}
1519

1620
echo "Done\n";
1721
?>
18-
--EXPECTF--
19-
Warning: register_shutdown_function(): Invalid shutdown callback 'test::__call' passed in %s on line %d
20-
bool(false)
22+
--EXPECT--
23+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, non-static method test::__call() cannot be called statically
2124
Done

ext/standard/tests/general_functions/bug32647.phpt

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,66 @@ class bar
1515
}
1616

1717
unset($obj);
18-
register_shutdown_function(array($obj,"")); // Invalid
19-
register_shutdown_function(array($obj,"some string")); // Invalid
20-
register_shutdown_function(array(0,"")); // Invalid
21-
register_shutdown_function(array('bar','foo')); // Invalid
22-
register_shutdown_function(array(0,"some string")); // Invalid
23-
register_shutdown_function('bar'); // Invalid
24-
register_shutdown_function('foo'); // Valid
25-
register_shutdown_function(array('bar','barfoo')); // Invalid
18+
try {
19+
register_shutdown_function(array($obj,"")); // Invalid
20+
} catch (\TypeError $e) {
21+
echo $e->getMessage() . \PHP_EOL;
22+
}
23+
try {
24+
register_shutdown_function(array($obj,"some string")); // Invalid
25+
} catch (\TypeError $e) {
26+
echo $e->getMessage() . \PHP_EOL;
27+
}
28+
try {
29+
register_shutdown_function(array(0,"")); // Invalid
30+
} catch (\TypeError $e) {
31+
echo $e->getMessage() . \PHP_EOL;
32+
}
33+
try {
34+
register_shutdown_function(array('bar','foo')); // Invalid
35+
} catch (\TypeError $e) {
36+
echo $e->getMessage() . \PHP_EOL;
37+
}
38+
try {
39+
register_shutdown_function(array(0,"some string")); // Invalid
40+
} catch (\TypeError $e) {
41+
echo $e->getMessage() . \PHP_EOL;
42+
}
43+
try {
44+
register_shutdown_function('bar'); // Invalid
45+
} catch (\TypeError $e) {
46+
echo $e->getMessage() . \PHP_EOL;
47+
}
48+
49+
register_shutdown_function('foo'); // Valid
50+
51+
try {
52+
register_shutdown_function(array('bar','barfoo')); // Invalid
53+
} catch (\TypeError $e) {
54+
echo $e->getMessage() . \PHP_EOL;
55+
}
2656

2757
$obj = new bar;
28-
register_shutdown_function(array($obj,'foobar')); // Invalid
29-
register_shutdown_function(array($obj,'barfoo')); // Valid
58+
try {
59+
register_shutdown_function(array($obj,'foobar')); // Invalid
60+
} catch (\TypeError $e) {
61+
echo $e->getMessage() . \PHP_EOL;
62+
}
63+
64+
register_shutdown_function(array($obj,'barfoo')); // Valid
3065

3166
?>
3267
--EXPECTF--
3368
Warning: Undefined variable $obj in %s on line %d
34-
35-
Warning: register_shutdown_function(): Invalid shutdown callback 'Array' passed in %s on line %d
69+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
3670

3771
Warning: Undefined variable $obj in %s on line %d
38-
39-
Warning: register_shutdown_function(): Invalid shutdown callback 'Array' passed in %s on line %d
40-
41-
Warning: register_shutdown_function(): Invalid shutdown callback 'Array' passed in %s on line %d
42-
43-
Warning: register_shutdown_function(): Invalid shutdown callback 'bar::foo' passed in %s on line %d
44-
45-
Warning: register_shutdown_function(): Invalid shutdown callback 'Array' passed in %s on line %d
46-
47-
Warning: register_shutdown_function(): Invalid shutdown callback 'bar' passed in %s on line %d
48-
49-
Warning: register_shutdown_function(): Invalid shutdown callback 'bar::barfoo' passed in %sbug32647.php on line %d
50-
51-
Warning: register_shutdown_function(): Invalid shutdown callback 'bar::foobar' passed in %sbug32647.php on line %d
72+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
73+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
74+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, class 'bar' does not have a method 'foo'
75+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, first array member is not a valid class name or object
76+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, function 'bar' not found or invalid function name
77+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, non-static method bar::barfoo() cannot be called statically
78+
register_shutdown_function(): Argument #1 ($function) must be a valid callback, class 'bar' does not have a method 'foobar'
5279
foo!
5380
bar!

0 commit comments

Comments
 (0)