Skip to content

Commit f4789c0

Browse files
committed
Use consumed_args for array_reduce and some other callback-using functions
1 parent ac620fd commit f4789c0

File tree

10 files changed

+126
-5
lines changed

10 files changed

+126
-5
lines changed

ext/pcre/php_pcre.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,7 @@ static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cach
15701570
fci->retval = &retval;
15711571
fci->param_count = 1;
15721572
fci->params = &arg;
1573+
fci->consumed_args = zend_fci_consumed_arg(0);
15731574
zend_call_function(fci, fcc);
15741575
zval_ptr_dtor(&arg);
15751576
if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
preg_replace_callback(): capture match array refcount stays low during callback
3+
--FILE--
4+
<?php
5+
var_dump(preg_replace_callback('/(.)(.)(.)/', static function ($matches) {
6+
debug_zval_dump($matches);
7+
return '';
8+
}, 'abc'));
9+
10+
var_dump(preg_replace_callback_array(['/(.)(.)(.)/' => static function ($matches) {
11+
debug_zval_dump($matches);
12+
return '';
13+
}], 'abc'));
14+
?>
15+
--EXPECTF--
16+
array(4) packed refcount(2){
17+
[0]=>
18+
string(3) "abc"%s
19+
[1]=>
20+
string(1) "a" interned
21+
[2]=>
22+
string(1) "b" interned
23+
[3]=>
24+
string(1) "c" interned
25+
}
26+
string(0) ""
27+
array(4) packed refcount(2){
28+
[0]=>
29+
string(3) "abc"%s
30+
[1]=>
31+
string(1) "a" interned
32+
[2]=>
33+
string(1) "b" interned
34+
[3]=>
35+
string(1) "c" interned
36+
}
37+
string(0) ""

ext/standard/array.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6414,6 +6414,7 @@ PHP_FUNCTION(array_reduce)
64146414
fci.retval = return_value;
64156415
fci.param_count = 2;
64166416
fci.params = args;
6417+
fci.consumed_args = zend_fci_consumed_arg(0);
64176418

64186419
ZEND_HASH_FOREACH_VAL(htbl, operand) {
64196420
ZVAL_COPY_VALUE(&args[0], return_value);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
array_reduce(): accumulator refcount stays low during callback
3+
--FILE--
4+
<?php
5+
6+
$result = array_reduce([1, 2, 3], function ($acc, $val) {
7+
debug_zval_dump($acc);
8+
$acc[] = $val;
9+
return $acc;
10+
}, []);
11+
12+
debug_zval_dump($result);
13+
14+
?>
15+
--EXPECT--
16+
array(0) interned {
17+
}
18+
array(1) packed refcount(2){
19+
[0]=>
20+
int(1)
21+
}
22+
array(2) packed refcount(2){
23+
[0]=>
24+
int(1)
25+
[1]=>
26+
int(2)
27+
}
28+
array(3) packed refcount(2){
29+
[0]=>
30+
int(1)
31+
[1]=>
32+
int(2)
33+
[2]=>
34+
int(3)
35+
}

ext/zend_test/test.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,21 @@ static ZEND_FUNCTION(zend_test_call_with_consumed_args)
603603
}
604604
}
605605

606+
static ZEND_FUNCTION(zend_test_refcount)
607+
{
608+
zval *value;
609+
610+
ZEND_PARSE_PARAMETERS_START(1, 1)
611+
Z_PARAM_ZVAL(value)
612+
ZEND_PARSE_PARAMETERS_END();
613+
614+
if (!Z_REFCOUNTED_P(value)) {
615+
RETURN_LONG(-1);
616+
}
617+
618+
RETURN_LONG(Z_REFCOUNT_P(value));
619+
}
620+
606621
static ZEND_FUNCTION(zend_get_unit_enum)
607622
{
608623
ZEND_PARSE_PARAMETERS_NONE();

ext/zend_test/test.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ function zend_call_method_if_exists(object $obj, string $method, mixed ...$args)
305305

306306
function zend_test_call_with_consumed_args(callable $cb, array $args, int $consumed_args): array {}
307307

308+
function zend_test_refcount(mixed $value): int {}
309+
308310
function zend_test_zend_ini_parse_quantity(string $str): int {}
309311
function zend_test_zend_ini_parse_uquantity(string $str): int {}
310312

ext/zend_test/test_arginfo.h

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/zend_test/test_decl.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
ob_start(): consumed callback arg has low refcount
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
$counts = [];
9+
ob_start(static function ($buffer) use (&$counts) {
10+
$counts[] = zend_test_refcount($buffer);
11+
return '';
12+
});
13+
echo 'abc';
14+
ob_end_flush();
15+
16+
var_dump($counts);
17+
18+
?>
19+
--EXPECT--
20+
array(1) {
21+
[0]=>
22+
int(2)
23+
}

main/output.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
972972
handler->func.user->fci.param_count = 2;
973973
handler->func.user->fci.params = ob_args;
974974
handler->func.user->fci.retval = &retval;
975+
handler->func.user->fci.consumed_args = zend_fci_consumed_arg(0);
975976

976977
if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) {
977978
if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) {

0 commit comments

Comments
 (0)