Skip to content

Commit cbc5fbd

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

11 files changed

Lines changed: 133 additions & 6 deletions

ext/pcre/php_pcre.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cach
15681568
fci->retval = &retval;
15691569
fci->param_count = 1;
15701570
fci->params = &arg;
1571+
fci->consumed_args = zend_fci_consumed_arg(0);
15711572
zend_call_function(fci, fcc);
15721573
zval_ptr_dtor(&arg);
15731574
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
@@ -6417,6 +6417,7 @@ PHP_FUNCTION(array_reduce)
64176417
fci.retval = return_value;
64186418
fci.param_count = 2;
64196419
fci.params = args;
6420+
fci.consumed_args = zend_fci_consumed_arg(0);
64206421

64216422
ZEND_HASH_FOREACH_VAL(htbl, operand) {
64226423
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
@@ -600,6 +600,21 @@ static ZEND_FUNCTION(zend_test_call_with_consumed_args)
600600
}
601601
}
602602

603+
static ZEND_FUNCTION(zend_test_refcount)
604+
{
605+
zval *value;
606+
607+
ZEND_PARSE_PARAMETERS_START(1, 1)
608+
Z_PARAM_ZVAL(value)
609+
ZEND_PARSE_PARAMETERS_END();
610+
611+
if (!Z_REFCOUNTED_P(value)) {
612+
RETURN_LONG(-1);
613+
}
614+
615+
RETURN_LONG(Z_REFCOUNT_P(value));
616+
}
617+
603618
static ZEND_FUNCTION(zend_get_unit_enum)
604619
{
605620
ZEND_PARSE_PARAMETERS_NONE();

ext/zend_test/test.stub.php

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

308308
function zend_test_call_with_consumed_args(callable $cb, array $args, int $consumed_args): array {}
309309

310+
function zend_test_refcount(mixed $value): int {}
311+
310312
function zend_test_zend_ini_parse_quantity(string $str): int {}
311313
function zend_test_zend_ini_parse_uquantity(string $str): int {}
312314

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.

ext/zend_test/test_legacy_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.
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+
}

0 commit comments

Comments
 (0)