mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Fix argument unpacking across stack pages
If multiple unpacks were used (or mixed with normal arguments) parts of the arguments could land on different stack pages. If this occurs the arguments will now be copied to a new stack page. The code used to do this is copied verbatim from the PHP 5.4 branch and only modified to reduce the amount of inlined code.
This commit is contained in:
parent
8ff4d61f08
commit
31a2ac470c
15
Zend/tests/arg_unpack/many_args.phpt
Normal file
15
Zend/tests/arg_unpack/many_args.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Argument unpacking with many arguments
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function fn(...$args) {
|
||||
var_dump(count($args));
|
||||
}
|
||||
|
||||
$array = array_fill(0, 10000, 42);
|
||||
fn(...$array, ...$array);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(20000)
|
@ -1691,6 +1691,42 @@ static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *oplin
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void **zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_vm_stack p = EG(argument_stack);
|
||||
|
||||
zend_vm_stack_extend(count + 1 TSRMLS_CC);
|
||||
|
||||
EG(argument_stack)->top += count;
|
||||
*(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
|
||||
while (count-- > 0) {
|
||||
void *data = *(--p->top);
|
||||
|
||||
if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) {
|
||||
zend_vm_stack r = p;
|
||||
|
||||
EG(argument_stack)->prev = p->prev;
|
||||
p = p->prev;
|
||||
efree(r);
|
||||
}
|
||||
*(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count) = data;
|
||||
}
|
||||
return EG(argument_stack)->top++;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count)
|
||||
|| UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) {
|
||||
return zend_vm_stack_push_args_with_copy(count TSRMLS_CC);
|
||||
}
|
||||
*(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
|
||||
return EG(argument_stack)->top++;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
#define ZEND_VM_NEXT_OPCODE() \
|
||||
CHECK_SYMBOL_TABLES() \
|
||||
ZEND_VM_INC_OPCODE(); \
|
||||
|
@ -1947,8 +1947,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
|
||||
}
|
||||
|
||||
num_args = opline->extended_value + EX(call)->num_additional_args;
|
||||
EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
|
||||
zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
|
||||
if (EX(call)->num_additional_args) {
|
||||
EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC);
|
||||
} else {
|
||||
EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
|
||||
zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
|
||||
}
|
||||
LOAD_OPLINE();
|
||||
|
||||
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
|
||||
|
@ -527,8 +527,12 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR
|
||||
}
|
||||
|
||||
num_args = opline->extended_value + EX(call)->num_additional_args;
|
||||
EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
|
||||
zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
|
||||
if (EX(call)->num_additional_args) {
|
||||
EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC);
|
||||
} else {
|
||||
EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
|
||||
zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
|
||||
}
|
||||
LOAD_OPLINE();
|
||||
|
||||
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
|
||||
|
Loading…
Reference in New Issue
Block a user