diff options
author | Nikita Popov <nikic@php.net> | 2013-08-29 11:35:11 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2014-01-11 12:42:08 +0100 |
commit | 2c47dfbaebb203ab547f3c7e786cb1db5e84674a (patch) | |
tree | 0afe28b1bc1a9de0861b61bbbe9eeceb289edfde | |
parent | c7bb28333804403c1e7cd817386ea1d527ad25e6 (diff) | |
download | php-git-2c47dfbaebb203ab547f3c7e786cb1db5e84674a.tar.gz |
Implement argument unpacking
RFC: https://wiki.php.net/rfc/argument_unpacking
-rw-r--r-- | Zend/tests/arg_unpack/basic.phpt | 114 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/by_ref.phpt | 149 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/dynamic.phpt | 37 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/internal.phpt | 43 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/invalid_type.phpt | 59 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/method.phpt | 45 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/new.phpt | 39 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/string_keys.phpt | 20 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/traversable_throwing_exception.phpt | 33 | ||||
-rw-r--r-- | Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt | 34 | ||||
-rw-r--r-- | Zend/zend_compile.c | 45 | ||||
-rw-r--r-- | Zend/zend_compile.h | 2 | ||||
-rw-r--r-- | Zend/zend_execute.c | 7 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 2 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 229 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 440 | ||||
-rw-r--r-- | Zend/zend_vm_opcodes.c | 3 | ||||
-rw-r--r-- | Zend/zend_vm_opcodes.h | 1 |
18 files changed, 1198 insertions, 104 deletions
diff --git a/Zend/tests/arg_unpack/basic.phpt b/Zend/tests/arg_unpack/basic.phpt new file mode 100644 index 0000000000..9c0365586a --- /dev/null +++ b/Zend/tests/arg_unpack/basic.phpt @@ -0,0 +1,114 @@ +--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], 6); +test(1, ...getArray([2, 3]), ...arrayGen([4, 5]), 6); + +test2(...[1, 2]); +test2(...[1, 2, 3]); +test2(...[1], ...[], ...[], ...[2, 3], 4, ...[5, 6]); + +?> +--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(6) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + [5]=> + int(6) +} +array(6) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + [5]=> + int(6) +} +int(1) +int(2) +NULL +int(1) +int(2) +int(3) +int(1) +int(2) +int(3) diff --git a/Zend/tests/arg_unpack/by_ref.phpt b/Zend/tests/arg_unpack/by_ref.phpt new file mode 100644 index 0000000000..0619a3bab8 --- /dev/null +++ b/Zend/tests/arg_unpack/by_ref.phpt @@ -0,0 +1,149 @@ +--TEST-- +Argument unpacking with by-ref arguments +--FILE-- +<?php + +error_reporting(E_ALL); + +function test1(&...$args) { + foreach ($args as &$arg) { + $arg++; + } +} + +test1(...[1, 2, 3]); + +$array = [1, 2, 3]; +test1(...$array); +var_dump($array); + +$array1 = [1, 2]; $val2 = 3; $array2 = [4, 5]; +test1(...$array1, $val2, ...$array2); +var_dump($array1, $val2, $array2); + +function test2($val1, &$ref1, $val2, &$ref2) { + $ref1++; + $ref2++; +} + +$array = [1, 2, 3, 4]; +test2(...$array); +var_dump($array); + +$a = $b = $c = $d = 0; + +$array = []; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$array = [1]; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$array = [1, 2]; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$array = [1, 2, 3]; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$vars = []; +$array = []; +test2(...$array, $vars['a'], $vars['b'], $vars['c'], $vars['d']); +var_dump($vars); + +$vars = []; +$array = [1]; +test2(...$array, $vars['a'], $vars['b'], $vars['c'], $vars['d']); +var_dump($vars); + +?> +--EXPECTF-- +array(3) { + [0]=> + int(2) + [1]=> + int(3) + [2]=> + int(4) +} +array(2) { + [0]=> + int(2) + [1]=> + int(3) +} +int(4) +array(2) { + [0]=> + int(5) + [1]=> + int(6) +} +array(4) { + [0]=> + int(1) + [1]=> + int(3) + [2]=> + int(3) + [3]=> + int(5) +} +array(0) { +} +int(0) +int(1) +int(0) +int(1) +array(1) { + [0]=> + int(1) +} +int(1) +int(1) +int(1) +int(1) +array(2) { + [0]=> + int(1) + [1]=> + int(3) +} +int(1) +int(2) +int(1) +int(1) +array(3) { + [0]=> + int(1) + [1]=> + int(3) + [2]=> + int(3) +} +int(2) +int(2) +int(1) +int(1) + +Notice: Undefined index: a in %s on line %d + +Notice: Undefined index: c in %s on line %d +array(2) { + ["b"]=> + int(1) + ["d"]=> + int(1) +} + +Notice: Undefined index: b in %s on line %d + +Notice: Undefined index: d in %s on line %d +array(2) { + ["a"]=> + int(1) + ["c"]=> + int(1) +} diff --git a/Zend/tests/arg_unpack/dynamic.phpt b/Zend/tests/arg_unpack/dynamic.phpt new file mode 100644 index 0000000000..efed84da78 --- /dev/null +++ b/Zend/tests/arg_unpack/dynamic.phpt @@ -0,0 +1,37 @@ +--TEST-- +Unpack arguments for dynamic call +--FILE-- +<?php + +$fn = function(...$args) { + var_dump($args); +}; + +$fn(...[]); +$fn(...[1, 2, 3]); +$fn(1, ...[2, 3], ...[], 4, 5); + +?> +--EXPECT-- +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) +} diff --git a/Zend/tests/arg_unpack/internal.phpt b/Zend/tests/arg_unpack/internal.phpt new file mode 100644 index 0000000000..adc985d940 --- /dev/null +++ b/Zend/tests/arg_unpack/internal.phpt @@ -0,0 +1,43 @@ +--TEST-- +Argument unpacking with internal functions +--FILE-- +<?php + +$arrays = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +]; +var_dump(array_map(null, ...$arrays)); + +?> +--EXPECT-- +array(3) { + [0]=> + array(3) { + [0]=> + int(1) + [1]=> + int(4) + [2]=> + int(7) + } + [1]=> + array(3) { + [0]=> + int(2) + [1]=> + int(5) + [2]=> + int(8) + } + [2]=> + array(3) { + [0]=> + int(3) + [1]=> + int(6) + [2]=> + int(9) + } +} diff --git a/Zend/tests/arg_unpack/invalid_type.phpt b/Zend/tests/arg_unpack/invalid_type.phpt new file mode 100644 index 0000000000..3efffebc76 --- /dev/null +++ b/Zend/tests/arg_unpack/invalid_type.phpt @@ -0,0 +1,59 @@ +--TEST-- +Only arrays and Traversables can be unpacked +--FILE-- +<?php + +function test(...$args) { + var_dump($args); +} + +test(...null); +test(...42); +test(...new stdClass); + +test(1, 2, 3, ..."foo", ...[4, 5]); +test(1, 2, ...new StdClass, 3, ...3.14, ...[4, 5]); + +?> +--EXPECTF-- +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(0) { +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(0) { +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(0) { +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} diff --git a/Zend/tests/arg_unpack/method.phpt b/Zend/tests/arg_unpack/method.phpt new file mode 100644 index 0000000000..d6a6e4712b --- /dev/null +++ b/Zend/tests/arg_unpack/method.phpt @@ -0,0 +1,45 @@ +--TEST-- +Unpack arguments for method calls +--FILE-- +<?php + +class Foo { + public function test(...$args) { + var_dump($args); + } + + public static function test2(...$args) { + var_dump($args); + } +} + +$foo = new Foo; +$foo->test(...[1, 2], 3, 4, ...[], 5); +Foo::test2(1, 2, ...[3, 4], ...[], 5); + +?> +--EXPECT-- +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) +} diff --git a/Zend/tests/arg_unpack/new.phpt b/Zend/tests/arg_unpack/new.phpt new file mode 100644 index 0000000000..3cf224f288 --- /dev/null +++ b/Zend/tests/arg_unpack/new.phpt @@ -0,0 +1,39 @@ +--TEST-- +Unpack arguments for new expression +--FILE-- +<?php + +class Foo { + public function __construct(...$args) { + var_dump($args); + } +} + +new Foo(...[]); +new Foo(...[1, 2, 3]); +new Foo(...[1], 2, ...[], ...[3, 4], 5); + +?> +--EXPECT-- +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) +} diff --git a/Zend/tests/arg_unpack/string_keys.phpt b/Zend/tests/arg_unpack/string_keys.phpt new file mode 100644 index 0000000000..443a882941 --- /dev/null +++ b/Zend/tests/arg_unpack/string_keys.phpt @@ -0,0 +1,20 @@ +--TEST-- +Argument unpacking does not work with string keys (forward compatibility for named args) +--FILE-- +<?php + +set_error_handler(function($errno, $errstr) { + var_dump($errstr); +}); + +var_dump(...[1, 2, "foo" => 3, 4]); +var_dump(...new ArrayIterator([1, 2, "foo" => 3, 4])); + +?> +--EXPECTF-- +string(36) "Cannot unpack array with string keys" +int(1) +int(2) +string(42) "Cannot unpack Traversable with string keys" +int(1) +int(2) diff --git a/Zend/tests/arg_unpack/traversable_throwing_exception.phpt b/Zend/tests/arg_unpack/traversable_throwing_exception.phpt new file mode 100644 index 0000000000..8ddc24dc74 --- /dev/null +++ b/Zend/tests/arg_unpack/traversable_throwing_exception.phpt @@ -0,0 +1,33 @@ +--TEST-- +Traversables that throw exceptions are properly handled during argument unpack +--FILE-- +<?php + +function test(...$args) { + var_dump($args); +} + +class Foo implements IteratorAggregate { + public function getIterator() { + throw new Exception('getIterator'); + } +} + +function gen() { + yield 1; + yield 2; + throw new Exception('gen'); +} + +try { + test(1, 2, ...new Foo, 3, 4); +} catch (Exception $e) { var_dump($e->getMessage()); } + +try { + test(1, 2, ...gen(), 3, 4); +} catch (Exception $e) { var_dump($e->getMessage()); } + +?> +--EXPECT-- +string(11) "getIterator" +string(3) "gen" diff --git a/Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt b/Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt new file mode 100644 index 0000000000..e862341652 --- /dev/null +++ b/Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt @@ -0,0 +1,34 @@ +--TEST-- +Traversables cannot be unpacked into by-reference parameters +--FILE-- +<?php + +function test($val1, $val2, $val3, &$ref) { + $ref = 42; +} + +function gen($array) { + foreach ($array as $element) { + yield $element; + } +} + +test(...gen([1, 2, 3]), $a); +var_dump($a); +test(1, 2, 3, $b, ...gen([4, 5, 6])); +var_dump($b); + +test(...gen([1, 2, 3, 4])); +test(1, 2, ...gen([3, 4])); +test(...gen([1, 2]), ...gen([3, 4])); + +?> +--EXPECTF-- +int(42) +int(42) + +Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d + +Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d + +Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9b12810b0a..f789e3397f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2549,8 +2549,11 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { + zend_function **function_ptr_ptr; + zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); - if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { + if (*function_ptr_ptr) { opline->opcode = ZEND_DO_FCALL; SET_NODE(opline->op1, function_name); SET_UNUSED(opline->op2); @@ -2562,6 +2565,13 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); opline->op2.num = --CG(context).nested_calls; + + /* This would normally be a ZEND_DO_FCALL, but was forced to use + * ZEND_DO_FCALL_BY_NAME due to a ... argument. In this case we need to + * free the function_name */ + if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { + zval_dtor(&function_name->u.constant); + } } } @@ -2687,6 +2697,39 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } /* }}} */ +void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */ +{ + zend_op *opline; + zend_function **function_ptr_ptr; + + zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); + if (*function_ptr_ptr) { + /* If argument unpacking is used argument numbers and sending modes can no longer be + * computed at compile time, thus we need access to EX(call). In order to have it we + * retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */ + zval func_name; + ZVAL_STRING(&func_name, (*function_ptr_ptr)->common.function_name, 1); + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_INIT_FCALL_BY_NAME; + opline->result.num = CG(context).nested_calls; + SET_UNUSED(opline->op1); + opline->op2_type = IS_CONST; + opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &func_name TSRMLS_CC); + GET_CACHE_SLOT(opline->op2.constant); + + ++CG(context).nested_calls; + *function_ptr_ptr = NULL; + } + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_SEND_UNPACK; + SET_NODE(opline->op1, params); + SET_UNUSED(opline->op2); + opline->op2.num = (zend_uint) offset; +} +/* }}} */ + static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */ { zend_op *opline; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a32a0c888b..f884df1946 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -383,6 +383,7 @@ typedef struct _call_slot { zend_function *fbc; zval *object; zend_class_entry *called_scope; + zend_uint num_additional_args; zend_bool is_ctor_call; zend_bool is_ctor_result_used; } call_slot; @@ -554,6 +555,7 @@ void zend_do_early_binding(TSRMLS_D); ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC); void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC); +void zend_do_unpack_params(znode *params, int offset TSRMLS_DC); void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 99bb5e02a9..172f1731d0 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1684,6 +1684,13 @@ ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array } /* }}} */ +zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, call_slot *call TSRMLS_DC) /* {{{ */ +{ + zend_uint arg_num = (opline->extended_value & ZEND_FETCH_ARG_MASK) + call->num_additional_args; + return ARG_SHOULD_BE_SENT_BY_REF(call->fbc, arg_num); +} +/* }}} */ + #define ZEND_VM_NEXT_OPCODE() \ CHECK_SYMBOL_TABLES() \ ZEND_VM_INC_OPCODE(); \ diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 752e27fff4..a4bc612bcb 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -585,9 +585,11 @@ non_empty_function_call_parameter_list: expr_without_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } | variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } | '&' w_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } + | T_ELLIPSIS expr { Z_LVAL($$.u.constant) = 0; zend_do_unpack_params(&$2, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' expr_without_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' '&' w_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$4, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } + | non_empty_function_call_parameter_list ',' T_ELLIPSIS expr { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant); zend_do_unpack_params(&$4, Z_LVAL($$.u.constant) TSRMLS_CC); } ; global_var_list: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 5969d8c1d1..37af82cef2 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1143,7 +1143,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) USE_OPLINE ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, - ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R); + zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R); } ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) @@ -1251,9 +1251,8 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV) SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -1488,7 +1487,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -1902,6 +1901,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) USE_OPLINE zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; + zend_uint num_args; SAVE_OPLINE(); EX(object) = EX(call)->object; @@ -1946,19 +1946,18 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EG(called_scope) = EX(call)->called_scope; } + 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)opline->extended_value TSRMLS_CC); + zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC); LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i=0; - zval **p = (zval**)EX(function_state).arguments; - ulong arg_count = opline->extended_value; + zend_uint i; + void **p = EX(function_state).arguments - num_args; - while (arg_count>0) { - zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); - arg_count--; + for (i = 0; i < num_args; ++i, ++p) { + zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC); } } @@ -1972,7 +1971,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(opline->extended_value, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC); } @@ -2022,7 +2021,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) /* Not sure what should be done here if it's a static method */ if (EXPECTED(EX(object) != NULL)) { - Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -2476,6 +2475,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2602,6 +2603,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2625,10 +2628,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -2653,10 +2659,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } efree(lcname); FREE_OP2(); + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && @@ -2673,8 +2682,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { FREE_OP2(); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && @@ -2740,8 +2752,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + FREE_OP2(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2779,7 +2794,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; + EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -2805,9 +2822,11 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } + call->fbc = EX(function_state).function; call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -3039,10 +3058,13 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) USE_OPLINE SAVE_OPLINE(); - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num); + } } + { zval *valptr; zval *value; @@ -3100,14 +3122,18 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) USE_OPLINE zend_free_op free_op1; zval *varptr; + int arg_num; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } else { + arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } } varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -3125,7 +3151,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -3162,9 +3188,11 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) } if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && - EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); @@ -3181,14 +3209,164 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) { USE_OPLINE - if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); + } } SAVE_OPLINE(); ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } +ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + int arg_num; + SAVE_OPLINE(); + + args = GET_OP1_ZVAL_PTR(BP_VAR_R); + arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + + switch (Z_TYPE_P(args)) { + case IS_ARRAY: { + HashTable *ht = Z_ARRVAL_P(args); + HashPosition pos; + zval **arg_ptr, *arg; + + ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + + for (zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void **) &arg_ptr, &pos) == SUCCESS; + zend_hash_move_forward_ex(ht, &pos), ++arg_num + ) { + char *name; + zend_uint name_len; + zend_ulong index; + + if (zend_hash_get_current_key_ex(ht, &name, &name_len, &index, 0, &pos) == HASH_KEY_IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys"); + FREE_OP1(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(arg_ptr); + arg = *arg_ptr; + Z_ADDREF_P(arg); + } else if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + } + break; + } + case IS_OBJECT: { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + break; + } + + iter = ce->get_iterator(ce, args, 0 TSRMLS_CC); + if (UNEXPECTED(!iter)) { + FREE_OP1(); + if (!EG(exception)) { + zend_throw_exception_ex( + NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name + ); + } + HANDLE_EXCEPTION(); + } + + if (iter->funcs->rewind) { + iter->funcs->rewind(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + } + + for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { + zval **arg_ptr, *arg; + + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + iter->funcs->get_current_data(iter, &arg_ptr TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + if (iter->funcs->get_current_key) { + zval key; + iter->funcs->get_current_key(iter, &key TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + if (Z_TYPE(key) == IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, + "Cannot unpack Traversable with string keys"); + zval_dtor(&key); + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + zval_dtor(&key); + } + + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error( + E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" + " by unpacking a Traversable, passing by-value instead", arg_num, + EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name : "", + EX(call)->fbc->common.scope ? "::" : "", + EX(call)->fbc->common.function_name + ); + } + + if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + ZEND_VM_STACK_GROW_IF_NEEDED(1); + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + + iter->funcs->move_forward(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + } + +ZEND_VM_C_LABEL(unpack_iter_dtor): + iter->funcs->dtor(iter TSRMLS_CC); + break; + } + default: + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + } + + FREE_OP1(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { USE_OPLINE @@ -3424,6 +3602,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) call->fbc = constructor; call->object = object_zval; call->called_scope = EX_T(opline->op1.var).class_entry; + call->num_additional_args = 0; call->is_ctor_call = 1; call->is_ctor_result_used = RETURN_VALUE_USED(opline); EX(call) = call; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index e9eda3e0a2..0651389f74 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -481,6 +481,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR USE_OPLINE zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; + zend_uint num_args; SAVE_OPLINE(); EX(object) = EX(call)->object; @@ -525,19 +526,18 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR EG(called_scope) = EX(call)->called_scope; } + 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)opline->extended_value TSRMLS_CC); + zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC); LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i=0; - zval **p = (zval**)EX(function_state).arguments; - ulong arg_count = opline->extended_value; + zend_uint i; + void **p = EX(function_state).arguments - num_args; - while (arg_count>0) { - zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); - arg_count--; + for (i = 0; i < num_args; ++i, ++p) { + zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC); } } @@ -551,7 +551,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(opline->extended_value, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC); } @@ -601,7 +601,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR /* Not sure what should be done here if it's a static method */ if (EXPECTED(EX(object) != NULL)) { - Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -701,6 +701,154 @@ static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER ZEND_VM_RETURN(); } +static int ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + int arg_num; + SAVE_OPLINE(); + + args = get_zval_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, BP_VAR_R); + arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + + switch (Z_TYPE_P(args)) { + case IS_ARRAY: { + HashTable *ht = Z_ARRVAL_P(args); + HashPosition pos; + zval **arg_ptr, *arg; + + ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + + for (zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void **) &arg_ptr, &pos) == SUCCESS; + zend_hash_move_forward_ex(ht, &pos), ++arg_num + ) { + char *name; + zend_uint name_len; + zend_ulong index; + + if (zend_hash_get_current_key_ex(ht, &name, &name_len, &index, 0, &pos) == HASH_KEY_IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys"); + FREE_OP(free_op1); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(arg_ptr); + arg = *arg_ptr; + Z_ADDREF_P(arg); + } else if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + } + break; + } + case IS_OBJECT: { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + break; + } + + iter = ce->get_iterator(ce, args, 0 TSRMLS_CC); + if (UNEXPECTED(!iter)) { + FREE_OP(free_op1); + if (!EG(exception)) { + zend_throw_exception_ex( + NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name + ); + } + HANDLE_EXCEPTION(); + } + + if (iter->funcs->rewind) { + iter->funcs->rewind(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + } + + for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { + zval **arg_ptr, *arg; + + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + iter->funcs->get_current_data(iter, &arg_ptr TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + if (iter->funcs->get_current_key) { + zval key; + iter->funcs->get_current_key(iter, &key TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + if (Z_TYPE(key) == IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, + "Cannot unpack Traversable with string keys"); + zval_dtor(&key); + goto unpack_iter_dtor; + } + + zval_dtor(&key); + } + + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error( + E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" + " by unpacking a Traversable, passing by-value instead", arg_num, + EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name : "", + EX(call)->fbc->common.scope ? "::" : "", + EX(call)->fbc->common.function_name + ); + } + + if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + ZEND_VM_STACK_GROW_IF_NEEDED(1); + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + + iter->funcs->move_forward(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + } + +unpack_iter_dtor: + iter->funcs->dtor(iter TSRMLS_CC); + break; + } + default: + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + } + + FREE_OP(free_op1); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -814,6 +962,7 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) call->fbc = constructor; call->object = object_zval; call->called_scope = EX_T(opline->op1.var).class_entry; + call->num_additional_args = 0; call->is_ctor_call = 1; call->is_ctor_result_used = RETURN_VALUE_USED(opline); EX(call) = call; @@ -1285,10 +1434,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1315,8 +1467,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && @@ -1333,8 +1487,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && @@ -1400,6 +1557,8 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -1439,7 +1598,9 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; + EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -1609,10 +1770,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1637,10 +1801,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } efree(lcname); zval_dtor(free_op2.var); + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && @@ -1657,8 +1824,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { zval_dtor(free_op2.var); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && @@ -1724,8 +1894,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + zval_dtor(free_op2.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1796,10 +1969,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1824,10 +2000,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } efree(lcname); zval_ptr_dtor_nogc(&free_op2.var); + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && @@ -1844,8 +2023,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { zval_ptr_dtor_nogc(&free_op2.var); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && @@ -1911,8 +2093,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + zval_ptr_dtor_nogc(&free_op2.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2021,10 +2206,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -2051,8 +2239,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && @@ -2069,8 +2259,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && @@ -2136,6 +2329,8 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2375,9 +2570,11 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } + call->fbc = EX(function_state).function; call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2534,10 +2731,13 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A USE_OPLINE SAVE_OPLINE(); - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num); + } } + { zval *valptr; zval *value; @@ -3542,7 +3742,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCO { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -3712,6 +3912,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -4695,6 +4897,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -5396,7 +5600,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5542,6 +5746,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -6131,7 +6337,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPC { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6260,6 +6466,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -7111,6 +7319,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -7819,10 +8029,13 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG USE_OPLINE SAVE_OPLINE(); - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num); + } } + { zval *valptr; zval *value; @@ -8880,7 +9093,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -9051,6 +9264,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -9899,6 +10114,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -10602,7 +10819,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -10748,6 +10965,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -11339,7 +11558,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCOD { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -12177,6 +12396,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -13040,14 +13261,18 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND USE_OPLINE zend_free_op free_op1; zval *varptr; + int arg_num; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -13065,7 +13290,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -13102,9 +13327,11 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && - EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); @@ -13121,9 +13348,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG { USE_OPLINE - if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SAVE_OPLINE(); return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -14738,7 +14967,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14846,9 +15075,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -15083,7 +15311,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -15395,6 +15623,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -15520,6 +15750,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -17169,9 +17401,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -17406,7 +17637,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -17719,6 +17950,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -17845,6 +18078,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -19290,7 +19525,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -19398,9 +19633,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -19635,7 +19869,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -20003,6 +20237,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -20129,6 +20365,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -21255,7 +21493,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCOD { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -21331,9 +21569,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_O SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -21554,6 +21791,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -22829,9 +23068,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -23066,7 +23304,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -23431,6 +23669,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -23556,6 +23796,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -24827,7 +25069,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CONST_HANDLER(ZEND { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -25049,6 +25291,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -26230,7 +26474,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_TMP_HANDLER(ZEND_O { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -26451,6 +26695,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -27537,7 +27783,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_VAR_HANDLER(ZEND_O { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -27758,6 +28004,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -29268,7 +29516,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CV_HANDLER(ZEND_OP { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -29488,6 +29736,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -30516,14 +30766,18 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL USE_OPLINE zval *varptr; + int arg_num; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); @@ -30541,7 +30795,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -30578,9 +30832,11 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && - EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); @@ -30596,9 +30852,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS { USE_OPLINE - if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SAVE_OPLINE(); return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -32067,7 +32325,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_ { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -32174,9 +32432,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -32408,7 +32665,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -32717,6 +32974,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -34264,9 +34523,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -34498,7 +34756,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -34808,6 +35066,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -36249,7 +36509,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HA { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -36356,9 +36616,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -36590,7 +36849,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -36954,6 +37213,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -38076,7 +38337,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -38151,9 +38412,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OP SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -39502,9 +39762,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -39736,7 +39995,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -40097,6 +40356,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -44788,6 +45049,31 @@ void zend_init_opcodes_handlers(void) ZEND_RECV_VARIADIC_SPEC_HANDLER, ZEND_RECV_VARIADIC_SPEC_HANDLER, ZEND_RECV_VARIADIC_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 3e8df979c8..d6f51cce5c 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include <stdio.h> #include <zend.h> -const char *zend_vm_opcodes_map[165] = { +const char *zend_vm_opcodes_map[166] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -187,6 +187,7 @@ const char *zend_vm_opcodes_map[165] = { "ZEND_FAST_CALL", "ZEND_FAST_RET", "ZEND_RECV_VARIADIC", + "ZEND_SEND_UNPACK", }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index e3e4f590d8..c4cab07aeb 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -170,5 +170,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_FAST_CALL 162 #define ZEND_FAST_RET 163 #define ZEND_RECV_VARIADIC 164 +#define ZEND_SEND_UNPACK 165 #endif
\ No newline at end of file |