Skip to content

Commit d1a3874

Browse files
committed
Fix SEND_UNPACK array separation
Separating only immutable arrays is not enough.
1 parent 15d1d4f commit d1a3874

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Array must be separated if unpacking by reference
3+
--FILE--
4+
<?php
5+
6+
function inc(&... $args) {
7+
foreach ($args as &$arg) {
8+
$arg++;
9+
}
10+
}
11+
12+
$arr = [1, 2];
13+
$arr[] = 3;
14+
$arr2 = $arr;
15+
inc(...$arr);
16+
var_dump($arr);
17+
var_dump($arr2);
18+
19+
?>
20+
--EXPECT--
21+
array(3) {
22+
[0]=>
23+
int(2)
24+
[1]=>
25+
int(3)
26+
[2]=>
27+
int(4)
28+
}
29+
array(3) {
30+
[0]=>
31+
int(1)
32+
[1]=>
33+
int(2)
34+
[2]=>
35+
int(3)
36+
}

Zend/zend_vm_def.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4422,7 +4422,7 @@ ZEND_VM_C_LABEL(send_again):
44224422

44234423
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht));
44244424

4425-
if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
4425+
if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_REFCOUNT_P(args) > 1) {
44264426
uint32_t i;
44274427
int separate = 0;
44284428

@@ -4434,7 +4434,7 @@ ZEND_VM_C_LABEL(send_again):
44344434
}
44354435
}
44364436
if (separate) {
4437-
zval_copy_ctor(args);
4437+
SEPARATE_ARRAY(args);
44384438
ht = Z_ARRVAL_P(args);
44394439
}
44404440
}
@@ -4448,7 +4448,7 @@ ZEND_VM_C_LABEL(send_again):
44484448

44494449
top = ZEND_CALL_ARG(EX(call), arg_num);
44504450
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
4451-
if (!Z_IMMUTABLE_P(args)) {
4451+
if (Z_REFCOUNT_P(args) == 1) {
44524452
ZVAL_MAKE_REF(arg);
44534453
Z_ADDREF_P(arg);
44544454
ZVAL_REF(top, Z_REF_P(arg));

Zend/zend_vm_execute.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
954954

955955
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht));
956956

957-
if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
957+
if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_REFCOUNT_P(args) > 1) {
958958
uint32_t i;
959959
int separate = 0;
960960

@@ -966,7 +966,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
966966
}
967967
}
968968
if (separate) {
969-
zval_copy_ctor(args);
969+
SEPARATE_ARRAY(args);
970970
ht = Z_ARRVAL_P(args);
971971
}
972972
}
@@ -980,7 +980,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
980980

981981
top = ZEND_CALL_ARG(EX(call), arg_num);
982982
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
983-
if (!Z_IMMUTABLE_P(args)) {
983+
if (Z_REFCOUNT_P(args) == 1) {
984984
ZVAL_MAKE_REF(arg);
985985
Z_ADDREF_P(arg);
986986
ZVAL_REF(top, Z_REF_P(arg));

0 commit comments

Comments
 (0)