diff options
| -rw-r--r-- | Zend/tests/arg_unpack/nested_by_ref.phpt | 22 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 10 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 6 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 6 |
4 files changed, 41 insertions, 3 deletions
diff --git a/Zend/tests/arg_unpack/nested_by_ref.phpt b/Zend/tests/arg_unpack/nested_by_ref.phpt new file mode 100644 index 0000000000..599c181c2c --- /dev/null +++ b/Zend/tests/arg_unpack/nested_by_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +By-ref unpacking of a nested access +--FILE-- +<?php + +function inc(&$var) { + $var++; +} + +$ary = [[1]]; +inc(...$ary[0]); +var_dump($ary); + +?> +--EXPECT-- +array(1) { + [0]=> + array(1) { + [0]=> + int(2) + } +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 10a6b294f7..dfa845cd73 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2963,7 +2963,15 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ uses_arg_unpack = 1; fbc = NULL; - zend_compile_expr(&arg_node, arg->child[0]); + /* Unpacking may need to create interior references in the unpacked array, + * but apart from that does not have any other reference semantics: It should + * generate a notice if the variable does not exist and it should not convert + * the variable itself into a reference. As such, use an RW fetch. */ + if (zend_is_variable(arg->child[0])) { + zend_compile_var(&arg_node, arg->child[0], BP_VAR_RW, 0); + } else { + zend_compile_expr(&arg_node, arg->child[0]); + } opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL); opline->op2.num = arg_count; opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_ARG(NULL, arg_count); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 930e1cc746..80c8ff68bc 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4920,7 +4920,11 @@ ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY) int arg_num; SAVE_OPLINE(); - args = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + if (OP1_TYPE & (IS_VAR|IS_CV)) { + args = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); + } else { + args = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + } arg_num = ZEND_CALL_NUM_ARGS(EX(call)) + 1; ZEND_VM_C_LABEL(send_again): diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6dfa6f2899..23d41dbdbd 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1862,7 +1862,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_ int arg_num; SAVE_OPLINE(); - args = get_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, BP_VAR_R); + if (opline->op1_type & (IS_VAR|IS_CV)) { + args = get_zval_ptr_ptr_undef(opline->op1_type, opline->op1, &free_op1, BP_VAR_RW); + } else { + args = get_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, BP_VAR_R); + } arg_num = ZEND_CALL_NUM_ARGS(EX(call)) + 1; send_again: |
