php-src/Zend/tests/arg_unpack/basic.phpt
Nikita Popov d3b484df82 Disallow use of positional args after unpacking
This commit disallows the use of trailing positional arguments
after argument unpacking was used. The following calls are no
longer valid:

    fn(...$array, $var);
    fn(...$array1, $var, ...$array2);

However, all of the following continue to be valid:

    fn($var, ...$array);
    fn(...$array1, ...$array2);
    fn($var, ...$array1, ...$array2);

The reason behind this change is a stack allocation issue pointed
out by Dmitry: As of PHP 5.5 the stack necessary for pushing
arguments is precomputed and preallocated, as such the individual
SEND opcodes no longer verify that there is enough stack space.
The unpacked arguments will occupy some of that preallocated
space and as such following positional arguments could write past
a stack page boundary.

An alternative resolution for this issue is to ensure that there
is enough space for the remaining arguments in the UNPACK opcode.
However making this allocation precise (rather than using a
conversative over-estimate) would require some effort. Given that
this particular aspect of the feature wasn't very popular in the
first place, it doesn't seem worth the effort.
2014-02-26 16:40:25 +01:00

111 lines
1.2 KiB
PHP

--TEST--
Basic argument unpacking
--FILE--
<?php
function test(...$args) {
var_dump($args);
}
function test2($arg1, $arg2, $arg3 = null) {
var_dump($arg1, $arg2, $arg3);
}
function getArray($array) {
return $array;
}
function arrayGen($array) {
foreach ($array as $element) {
yield $element;
}
}
$array = [1, 2, 3];
test(...[]);
test(...[1, 2, 3]);
test(...$array);
test(...getArray([1, 2, 3]));
test(...arrayGen([]));
test(...arrayGen([1, 2, 3]));
test(1, ...[2, 3], ...[4, 5]);
test(1, ...getArray([2, 3]), ...arrayGen([4, 5]));
test2(...[1, 2]);
test2(...[1, 2, 3]);
test2(...[1], ...[], ...[], ...[2, 3], ...[4, 5]);
?>
--EXPECT--
array(0) {
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(0) {
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
int(1)
int(2)
NULL
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)