com php-src: Fix argument unpacking across stack pages: Zend/tests/arg_unpack/many_args.phpt Zend/zend_execut e.c Zend/zend_vm_def.h
Zend/zend_vm_execute.h
| From: | Nikita Popov | Date: | Sat, 18 Jan 2014 13:41:33 +0000 |
| Subject: | com php-src: Fix argument unpacking across stack pages: Zend/tests/arg_unpack/many_args.phpt Zend/zend_execut e.c Zend/zend_vm_def.h Zend/zend_vm_execute.h |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-75686@lists.php.net to get a copy of this message | ||
Commit: 31a2ac470cba47a396a9b6c815700fbec51c6032
Author: Nikita Popov <nikic@php.net> Sat, 18 Jan 2014 12:30:44 +0100
Parents: 8ff4d61f0864fbca7b2905f14de76fd400d9b3df
Branches: PHP-5.6 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=31a2ac470cba47a396a9b6c815700fbec51c6032
Log:
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.
Changed paths:
A Zend/tests/arg_unpack/many_args.phpt
M Zend/zend_execute.c
M Zend/zend_vm_def.h
M Zend/zend_vm_execute.h
Diff:
diff --git a/Zend/tests/arg_unpack/many_args.phpt b/Zend/tests/arg_unpack/many_args.phpt
new file mode 100644
index 0000000..0ef5a30
--- /dev/null
+++ b/Zend/tests/arg_unpack/many_args.phpt
@@ -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)
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 174b165..31cacee 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -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(); \
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 37af82c..1e8a831 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -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) {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 0651389..7e613cd 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -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) {