1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-11406: segfault with unpacking and magic method closure

The magic method trampoline closure may be variadic. However, the
arg_info for the variadic argument was not set, resulting in a crash
both in reflection and in the VM.

Fix it by creating an arg_info containing a single element in case of
the variadic case. The variadic argument is the last one (and in this
case only one) in the arg_info array.

We make sure the argument info is equivalent to the argument info of
`$closure` of the following code snippet:
```
function foo(...$arguments) {}
$closure = foo(...);
```

Closes GH-11417.
This commit is contained in:
Niels Dossche
2023-06-09 17:06:24 +02:00
committed by nielsdos
parent 18f2f0a0ab
commit 5c789806ef
3 changed files with 43 additions and 0 deletions

2
NEWS
View File

@@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fix GH-11388 (Allow "final" modifier when importing a method from a trait).
(nielsdos)
. Fixed bug GH-11406 (segfault with unpacking and magic method closure).
(nielsdos)
- DOM:
. Fix #79700 (wrong use of libxml oldNs leads to performance problem).

View File

@@ -14,12 +14,15 @@ class Test {
$test = new Test;
$array = ["unpacked"];
echo "-- Non-static cases --\n";
$test->test(1, 2, a: 123);
$test->test(...)(1, 2);
$test->test(...)(1, 2, a: 123, b: $test);
$test->test(...)(a: 123, b: $test);
$test->test(...)();
$test->test(...)(...$array);
echo "-- Static cases --\n";
Test::testStatic(1, 2, a: 123);
@@ -27,6 +30,16 @@ Test::testStatic(...)(1, 2);
Test::testStatic(...)(1, 2, a: 123, b: $test);
Test::testStatic(...)(a: 123, b: $test);
Test::testStatic(...)();
Test::testStatic(...)(...$array);
echo "-- Reflection tests --\n";
$reflectionFunction = new ReflectionFunction(Test::fail(...));
var_dump($reflectionFunction->getParameters());
$argument = $reflectionFunction->getParameters()[0];
var_dump($argument->isVariadic());
$type = $argument->getType();
var_dump($type);
var_dump($type->getName());
?>
--EXPECT--
@@ -70,6 +83,11 @@ array(2) {
string(4) "test"
array(0) {
}
string(4) "test"
array(1) {
[0]=>
string(8) "unpacked"
}
-- Static cases --
string(10) "testStatic"
array(3) {
@@ -110,3 +128,20 @@ array(2) {
string(10) "testStatic"
array(0) {
}
string(10) "testStatic"
array(1) {
[0]=>
string(8) "unpacked"
}
-- Reflection tests --
array(1) {
[0]=>
object(ReflectionParameter)#4 (1) {
["name"]=>
string(9) "arguments"
}
}
bool(true)
object(ReflectionNamedType)#5 (0) {
}
string(5) "mixed"

View File

@@ -833,6 +833,9 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas
}
/* }}} */
/* __call and __callStatic name the arguments "$arguments" in the docs. */
static zend_internal_arg_info trampoline_arg_info[] = {ZEND_ARG_VARIADIC_TYPE_INFO(false, arguments, IS_MIXED, false)};
void zend_closure_from_frame(zval *return_value, zend_execute_data *call) { /* {{{ */
zval instance;
zend_internal_function trampoline;
@@ -856,6 +859,9 @@ void zend_closure_from_frame(zval *return_value, zend_execute_data *call) { /* {
trampoline.handler = zend_closure_call_magic;
trampoline.function_name = mptr->common.function_name;
trampoline.scope = mptr->common.scope;
if (trampoline.fn_flags & ZEND_ACC_VARIADIC) {
trampoline.arg_info = trampoline_arg_info;
}
zend_free_trampoline(mptr);
mptr = (zend_function *) &trampoline;