Skip to content

Commit 05e6f3e

Browse files
authored
Refactor register_tick_function mechanism (php#5828)
1 parent cc2c810 commit 05e6f3e

File tree

3 files changed

+44
-67
lines changed

3 files changed

+44
-67
lines changed

ext/standard/basic_functions.c

Lines changed: 29 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ PHPAPI php_basic_globals basic_globals;
110110
#include "basic_functions_arginfo.h"
111111

112112
typedef struct _user_tick_function_entry {
113-
zval *arguments;
114-
int arg_count;
115-
int calling;
113+
zend_fcall_info fci;
114+
zend_fcall_info_cache fci_cache;
115+
bool calling;
116116
} user_tick_function_entry;
117117

118118
/* some prototypes for local functions */
@@ -1678,12 +1678,12 @@ void user_shutdown_function_dtor(zval *zv) /* {{{ */
16781678

16791679
void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {{{ */
16801680
{
1681-
int i;
1682-
1683-
for (i = 0; i < tick_function_entry->arg_count; i++) {
1684-
zval_ptr_dtor(&tick_function_entry->arguments[i]);
1681+
zval_ptr_dtor(&tick_function_entry->fci.function_name);
1682+
for (size_t i = 0; i < tick_function_entry->fci.param_count; i++) {
1683+
zval_ptr_dtor(&tick_function_entry->fci.params[i]);
16851684
}
1686-
efree(tick_function_entry->arguments);
1685+
1686+
efree(tick_function_entry);
16871687
}
16881688
/* }}} */
16891689

@@ -1713,27 +1713,19 @@ static int user_shutdown_function_call(zval *zv) /* {{{ */
17131713

17141714
static void user_tick_function_call(user_tick_function_entry *tick_fe) /* {{{ */
17151715
{
1716-
zval retval;
1717-
zval *function = &tick_fe->arguments[0];
1718-
1719-
/* Prevent reentrant calls to the same user ticks function */
1720-
if (! tick_fe->calling) {
1721-
tick_fe->calling = 1;
1722-
1723-
if (call_user_function(NULL, NULL,
1724-
function,
1725-
&retval,
1726-
tick_fe->arg_count - 1,
1727-
tick_fe->arguments + 1
1728-
) == SUCCESS) {
1729-
zval_ptr_dtor(&retval);
1730-
} else {
1731-
zend_string *function_name = zend_get_callable_name(function);
1732-
zend_throw_error(NULL, "Registered tick function %s() cannot be called, function does not exist", ZSTR_VAL(function_name));
1733-
zend_string_release(function_name);
1734-
}
1716+
/* Prevent re-entrant calls to the same user ticks function */
1717+
if (!tick_fe->calling) {
1718+
zval tmp;
1719+
1720+
/* set tmp zval */
1721+
tick_fe->fci.retval = &tmp;
17351722

1736-
tick_fe->calling = 0;
1723+
tick_fe->calling = true;
1724+
zend_call_function(&tick_fe->fci, &tick_fe->fci_cache);
1725+
1726+
/* Destroy return value */
1727+
zval_ptr_dtor(&tmp);
1728+
tick_fe->calling = false;
17371729
}
17381730
}
17391731
/* }}} */
@@ -1746,8 +1738,8 @@ static void run_user_tick_functions(int tick_count, void *arg) /* {{{ */
17461738

17471739
static int user_tick_function_compare(user_tick_function_entry * tick_fe1, user_tick_function_entry * tick_fe2) /* {{{ */
17481740
{
1749-
zval *func1 = &tick_fe1->arguments[0];
1750-
zval *func2 = &tick_fe2->arguments[0];
1741+
zval *func1 = &tick_fe1->fci.function_name;
1742+
zval *func2 = &tick_fe2->fci.function_name;
17511743
int ret;
17521744

17531745
if (Z_TYPE_P(func1) == IS_STRING && Z_TYPE_P(func2) == IS_STRING) {
@@ -2387,36 +2379,17 @@ PHP_FUNCTION(getprotobynumber)
23872379
PHP_FUNCTION(register_tick_function)
23882380
{
23892381
user_tick_function_entry tick_fe;
2390-
int i;
2391-
zend_string *function_name = NULL;
2392-
2393-
tick_fe.calling = 0;
2394-
tick_fe.arg_count = ZEND_NUM_ARGS();
23952382

2396-
if (tick_fe.arg_count < 1) {
2397-
WRONG_PARAM_COUNT;
2398-
}
2399-
2400-
tick_fe.arguments = (zval *) safe_emalloc(sizeof(zval), tick_fe.arg_count, 0);
2401-
2402-
if (zend_get_parameters_array(ZEND_NUM_ARGS(), tick_fe.arg_count, tick_fe.arguments) == FAILURE) {
2403-
efree(tick_fe.arguments);
2404-
RETURN_FALSE;
2405-
}
2406-
2407-
if (!zend_is_callable(&tick_fe.arguments[0], 0, &function_name)) {
2408-
efree(tick_fe.arguments);
2409-
zend_argument_type_error(1, "must be a valid tick callback, \"%s\" given", ZSTR_VAL(function_name));
2410-
zend_string_release_ex(function_name, 0);
2383+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &tick_fe.fci, &tick_fe.fci_cache,
2384+
&tick_fe.fci.params, &tick_fe.fci.param_count) == FAILURE) {
24112385
RETURN_THROWS();
2412-
} else if (function_name) {
2413-
zend_string_release_ex(function_name, 0);
24142386
}
24152387

2416-
if (Z_TYPE(tick_fe.arguments[0]) != IS_ARRAY && Z_TYPE(tick_fe.arguments[0]) != IS_OBJECT) {
2417-
convert_to_string(&tick_fe.arguments[0]);
2388+
tick_fe.calling = false;
2389+
Z_TRY_ADDREF(tick_fe.fci.function_name);
2390+
for (size_t i = 0; i < tick_fe.fci.param_count; i++) {
2391+
Z_TRY_ADDREF(tick_fe.fci.params[i]);
24182392
}
2419-
24202393
if (!BG(user_tick_functions)) {
24212394
BG(user_tick_functions) = (zend_llist *) emalloc(sizeof(zend_llist));
24222395
zend_llist_init(BG(user_tick_functions),
@@ -2425,10 +2398,6 @@ PHP_FUNCTION(register_tick_function)
24252398
php_add_tick_function(run_user_tick_functions, NULL);
24262399
}
24272400

2428-
for (i = 0; i < tick_fe.arg_count; i++) {
2429-
Z_TRY_ADDREF(tick_fe.arguments[i]);
2430-
}
2431-
24322401
zend_llist_add_element(BG(user_tick_functions), &tick_fe);
24332402

24342403
RETURN_TRUE;
@@ -2439,22 +2408,16 @@ PHP_FUNCTION(register_tick_function)
24392408
PHP_FUNCTION(unregister_tick_function)
24402409
{
24412410
user_tick_function_entry tick_fe;
2442-
zend_fcall_info fci;
2443-
zend_fcall_info_cache fci_cache;
24442411

24452412
ZEND_PARSE_PARAMETERS_START(1, 1)
2446-
Z_PARAM_FUNC(fci, fci_cache)
2413+
Z_PARAM_FUNC(tick_fe.fci, tick_fe.fci_cache)
24472414
ZEND_PARSE_PARAMETERS_END();
24482415

24492416
if (!BG(user_tick_functions)) {
24502417
return;
24512418
}
24522419

2453-
tick_fe.arguments = (zval *) emalloc(sizeof(zval));
2454-
ZVAL_COPY_VALUE(&tick_fe.arguments[0], &fci.function_name);
2455-
tick_fe.arg_count = 1;
24562420
zend_llist_del_element(BG(user_tick_functions), &tick_fe, (int (*)(void *, void *)) user_tick_function_compare);
2457-
efree(tick_fe.arguments);
24582421
}
24592422
/* }}} */
24602423

ext/standard/tests/general_functions/register_tick_function_error.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ try {
1111
}
1212
?>
1313
--EXPECT--
14-
register_tick_function(): Argument #1 ($callback) must be a valid tick callback, "a" given
14+
register_tick_function(): Argument #1 ($callback) must be a valid callback, function "a" not found or invalid function name
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
unregister_tick_function only accepts a valid callback as parameter
3+
--FILE--
4+
<?php
5+
declare(ticks=1);
6+
7+
try {
8+
unregister_tick_function("a");
9+
} catch (TypeError $exception) {
10+
echo $exception->getMessage() . "\n";
11+
}
12+
?>
13+
--EXPECT--
14+
unregister_tick_function(): Argument #1 ($callback) must be a valid callback, function "a" not found or invalid function name

0 commit comments

Comments
 (0)