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:
2
NEWS
2
NEWS
@@ -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).
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user