mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Refactor register shutdown function mechanism
Use FCI/FCC structure instead of custom implementation which does the same. This also fixes the "bug" which prevented static methods from being shutdown functions. Closes GH-5829 Co-authored-by: Aaron Piotrowski <aaron@trowski.com>
This commit is contained in:
parent
fcd18757b2
commit
a9695cc615
5 changed files with 39 additions and 50 deletions
|
@ -12,7 +12,7 @@ class try_class
|
||||||
|
|
||||||
static public function on_shutdown ()
|
static public function on_shutdown ()
|
||||||
{
|
{
|
||||||
printf ("CHECKPOINT\n"); /* never reached */
|
printf ("CHECKPOINT\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,5 +22,4 @@ echo "Done\n";
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
Done
|
Done
|
||||||
|
CHECKPOINT
|
||||||
Fatal error: Registered shutdown function self::on_shutdown() cannot be called, function does not exist in Unknown on line 0
|
|
||||||
|
|
|
@ -2047,13 +2047,18 @@ PHP_FUNCTION(session_set_save_handler)
|
||||||
if (register_shutdown) {
|
if (register_shutdown) {
|
||||||
/* create shutdown function */
|
/* create shutdown function */
|
||||||
php_shutdown_function_entry shutdown_function_entry;
|
php_shutdown_function_entry shutdown_function_entry;
|
||||||
ZVAL_STRING(&shutdown_function_entry.function_name, "session_register_shutdown");
|
zval callable;
|
||||||
shutdown_function_entry.arg_count = 0;
|
zend_result result;
|
||||||
shutdown_function_entry.arguments = NULL;
|
|
||||||
|
ZVAL_STRING(&callable, "session_register_shutdown");
|
||||||
|
result = zend_fcall_info_init(&callable, 0, &shutdown_function_entry.fci,
|
||||||
|
&shutdown_function_entry.fci_cache, NULL, NULL);
|
||||||
|
|
||||||
|
ZEND_ASSERT(result == SUCCESS);
|
||||||
|
|
||||||
/* add shutdown function, removing the old one if it exists */
|
/* add shutdown function, removing the old one if it exists */
|
||||||
if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry)) {
|
if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry)) {
|
||||||
zval_ptr_dtor(&shutdown_function_entry.function_name);
|
zval_ptr_dtor(&callable);
|
||||||
php_error_docref(NULL, E_WARNING, "Unable to register session shutdown function");
|
php_error_docref(NULL, E_WARNING, "Unable to register session shutdown function");
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -2654,6 +2659,8 @@ PHP_FUNCTION(session_status)
|
||||||
PHP_FUNCTION(session_register_shutdown)
|
PHP_FUNCTION(session_register_shutdown)
|
||||||
{
|
{
|
||||||
php_shutdown_function_entry shutdown_function_entry;
|
php_shutdown_function_entry shutdown_function_entry;
|
||||||
|
zval callable;
|
||||||
|
zend_result result;
|
||||||
|
|
||||||
ZEND_PARSE_PARAMETERS_NONE();
|
ZEND_PARSE_PARAMETERS_NONE();
|
||||||
|
|
||||||
|
@ -2663,13 +2670,14 @@ PHP_FUNCTION(session_register_shutdown)
|
||||||
* function after calling session_set_save_handler(), which expects
|
* function after calling session_set_save_handler(), which expects
|
||||||
* the session still to be available.
|
* the session still to be available.
|
||||||
*/
|
*/
|
||||||
|
ZVAL_STRING(&callable, "session_write_close");
|
||||||
|
result = zend_fcall_info_init(&callable, 0, &shutdown_function_entry.fci,
|
||||||
|
&shutdown_function_entry.fci_cache, NULL, NULL);
|
||||||
|
|
||||||
ZVAL_STRING(&shutdown_function_entry.function_name, "session_write_close");
|
ZEND_ASSERT(result == SUCCESS);
|
||||||
shutdown_function_entry.arg_count = 0;
|
|
||||||
shutdown_function_entry.arguments = NULL;
|
|
||||||
|
|
||||||
if (!append_user_shutdown_function(&shutdown_function_entry)) {
|
if (!append_user_shutdown_function(&shutdown_function_entry)) {
|
||||||
zval_ptr_dtor(&shutdown_function_entry.function_name);
|
zval_ptr_dtor(&callable);
|
||||||
|
|
||||||
/* Unable to register shutdown function, presumably because of lack
|
/* Unable to register shutdown function, presumably because of lack
|
||||||
* of memory, so flush the session now. It would be done in rshutdown
|
* of memory, so flush the session now. It would be done in rshutdown
|
||||||
|
|
|
@ -1664,14 +1664,10 @@ PHP_FUNCTION(forward_static_call_array)
|
||||||
|
|
||||||
void user_shutdown_function_dtor(zval *zv) /* {{{ */
|
void user_shutdown_function_dtor(zval *zv) /* {{{ */
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
|
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
|
||||||
|
|
||||||
zval_ptr_dtor(&shutdown_function_entry->function_name);
|
zval_ptr_dtor(&shutdown_function_entry->fci.function_name);
|
||||||
for (i = 0; i < shutdown_function_entry->arg_count; i++) {
|
zend_fcall_info_args_clear(&shutdown_function_entry->fci, true);
|
||||||
zval_ptr_dtor(&shutdown_function_entry->arguments[i]);
|
|
||||||
}
|
|
||||||
efree(shutdown_function_entry->arguments);
|
|
||||||
efree(shutdown_function_entry);
|
efree(shutdown_function_entry);
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -1685,24 +1681,16 @@ void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {
|
||||||
|
|
||||||
static int user_shutdown_function_call(zval *zv) /* {{{ */
|
static int user_shutdown_function_call(zval *zv) /* {{{ */
|
||||||
{
|
{
|
||||||
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
|
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
|
||||||
zval retval;
|
zval retval;
|
||||||
|
zend_result call_status;
|
||||||
|
|
||||||
if (!zend_is_callable(&shutdown_function_entry->function_name, 0, NULL)) {
|
/* set retval zval for FCI struct */
|
||||||
zend_string *function_name = zend_get_callable_name(&shutdown_function_entry->function_name);
|
shutdown_function_entry->fci.retval = &retval;
|
||||||
zend_throw_error(NULL, "Registered shutdown function %s() cannot be called, function does not exist", ZSTR_VAL(function_name));
|
call_status = zend_call_function(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
|
||||||
zend_string_release(function_name);
|
ZEND_ASSERT(call_status == SUCCESS);
|
||||||
return 0;
|
zval_ptr_dtor(&retval);
|
||||||
}
|
|
||||||
|
|
||||||
if (call_user_function(NULL, NULL,
|
|
||||||
&shutdown_function_entry->function_name,
|
|
||||||
&retval,
|
|
||||||
shutdown_function_entry->arg_count,
|
|
||||||
shutdown_function_entry->arguments) == SUCCESS)
|
|
||||||
{
|
|
||||||
zval_ptr_dtor(&retval);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -1761,8 +1749,7 @@ PHPAPI void php_call_shutdown_functions(void) /* {{{ */
|
||||||
if (BG(user_shutdown_function_names)) {
|
if (BG(user_shutdown_function_names)) {
|
||||||
zend_try {
|
zend_try {
|
||||||
zend_hash_apply(BG(user_shutdown_function_names), user_shutdown_function_call);
|
zend_hash_apply(BG(user_shutdown_function_names), user_shutdown_function_call);
|
||||||
}
|
} zend_end_try();
|
||||||
zend_end_try();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -1786,23 +1773,19 @@ PHPAPI void php_free_shutdown_functions(void) /* {{{ */
|
||||||
PHP_FUNCTION(register_shutdown_function)
|
PHP_FUNCTION(register_shutdown_function)
|
||||||
{
|
{
|
||||||
php_shutdown_function_entry entry;
|
php_shutdown_function_entry entry;
|
||||||
zend_fcall_info fci;
|
zval *params = NULL;
|
||||||
zend_fcall_info_cache fcc;
|
uint32_t param_count = 0;
|
||||||
zval *args;
|
bool status;
|
||||||
int arg_count = 0;
|
|
||||||
|
|
||||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &fci, &fcc, &args, &arg_count) == FAILURE) {
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &entry.fci, &entry.fci_cache, ¶ms, ¶m_count) == FAILURE) {
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZVAL_COPY(&entry.function_name, &fci.function_name);
|
Z_TRY_ADDREF(entry.fci.function_name);
|
||||||
entry.arguments = (zval *) safe_emalloc(sizeof(zval), arg_count, 0);
|
zend_fcall_info_argp(&entry.fci, param_count, params);
|
||||||
entry.arg_count = arg_count;
|
|
||||||
for (int i = 0; i < arg_count; i++) {
|
|
||||||
ZVAL_COPY(&entry.arguments[i], &args[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
append_user_shutdown_function(&entry);
|
status = append_user_shutdown_function(&entry);
|
||||||
|
ZEND_ASSERT(status);
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
|
|
@ -143,9 +143,8 @@ PHPAPI double php_get_nan(void);
|
||||||
PHPAPI double php_get_inf(void);
|
PHPAPI double php_get_inf(void);
|
||||||
|
|
||||||
typedef struct _php_shutdown_function_entry {
|
typedef struct _php_shutdown_function_entry {
|
||||||
zval function_name;
|
zend_fcall_info fci;
|
||||||
zval *arguments;
|
zend_fcall_info_cache fci_cache;
|
||||||
int arg_count;
|
|
||||||
} php_shutdown_function_entry;
|
} php_shutdown_function_entry;
|
||||||
|
|
||||||
PHPAPI extern bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry);
|
PHPAPI extern bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry);
|
||||||
|
|
|
@ -12,7 +12,7 @@ class test {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
register_shutdown_function(array("test","__call"));
|
var_dump(register_shutdown_function(array("test","__call")));
|
||||||
} catch (TypeError $exception) {
|
} catch (TypeError $exception) {
|
||||||
echo $exception->getMessage() . "\n";
|
echo $exception->getMessage() . "\n";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue