Skip to content

Commit fabcc9a

Browse files
committed
Fix long-term shutdown/tick fci/fcc storage
Normally incrementing the refcount on just function_name is sufficient. However, if the callable is of the form 'X::y' inside an instance method, this will capture $this in fcc.object, which also needs to be retained. The fci_addref/fci_release helpers should likely be exported as a general API, as we may have this problem in other places as well. Fixes oss-fuzz #39778.
1 parent bbe2136 commit fabcc9a

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
register_shutdown_function() and long-term fci storage
3+
--FILE--
4+
<?php
5+
class Test {
6+
function register() {
7+
register_shutdown_function('Test::method');
8+
}
9+
function method() {
10+
var_dump($this);
11+
}
12+
}
13+
(new Test)->register();
14+
?>
15+
--EXPECT--
16+
object(Test)#1 (0) {
17+
}

ext/standard/basic_functions.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,20 +1665,36 @@ PHP_FUNCTION(forward_static_call_array)
16651665
}
16661666
/* }}} */
16671667

1668+
static void fci_addref(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1669+
{
1670+
Z_TRY_ADDREF(fci->function_name);
1671+
if (fci_cache->object) {
1672+
GC_ADDREF(fci_cache->object);
1673+
}
1674+
}
1675+
1676+
static void fci_release(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1677+
{
1678+
zval_ptr_dtor(&fci->function_name);
1679+
if (fci_cache->object) {
1680+
zend_object_release(fci_cache->object);
1681+
}
1682+
}
1683+
16681684
void user_shutdown_function_dtor(zval *zv) /* {{{ */
16691685
{
16701686
php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
16711687

1672-
zval_ptr_dtor(&shutdown_function_entry->fci.function_name);
16731688
zend_fcall_info_args_clear(&shutdown_function_entry->fci, true);
1689+
fci_release(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
16741690
efree(shutdown_function_entry);
16751691
}
16761692
/* }}} */
16771693

16781694
void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {{{ */
16791695
{
1680-
zval_ptr_dtor(&tick_function_entry->fci.function_name);
16811696
zend_fcall_info_args_clear(&tick_function_entry->fci, true);
1697+
fci_release(&tick_function_entry->fci, &tick_function_entry->fci_cache);
16821698
}
16831699
/* }}} */
16841700

@@ -1784,7 +1800,7 @@ PHP_FUNCTION(register_shutdown_function)
17841800
RETURN_THROWS();
17851801
}
17861802

1787-
Z_TRY_ADDREF(entry.fci.function_name);
1803+
fci_addref(&entry.fci, &entry.fci_cache);
17881804
zend_fcall_info_argp(&entry.fci, param_count, params);
17891805

17901806
status = append_user_shutdown_function(&entry);
@@ -2353,7 +2369,7 @@ PHP_FUNCTION(register_tick_function)
23532369
}
23542370

23552371
tick_fe.calling = false;
2356-
Z_TRY_ADDREF(tick_fe.fci.function_name);
2372+
fci_addref(&tick_fe.fci, &tick_fe.fci_cache);
23572373
zend_fcall_info_argp(&tick_fe.fci, param_count, params);
23582374

23592375
if (!BG(user_tick_functions)) {

0 commit comments

Comments
 (0)