Skip to content

Commit 61d00a6

Browse files
nikickrakjoe
authored andcommitted
Use COPY_DEREF instead of COPY_UNREF
This fixes the behavior when the storage location of the fetch is modified before the operand is dereferenced by the using VM opcode. Furthermore it elimiates references as a possible return value from *_R opcodes, which will give us more opportunities for inferences, in particular in regard to typed properties.
1 parent da82719 commit 61d00a6

File tree

6 files changed

+124
-93
lines changed

6 files changed

+124
-93
lines changed

Zend/tests/bug72543_5.phpt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ Bug #72543.5 (different references behavior comparing to PHP 5)
55
$arr = [1];
66
$ref =& $arr[0];
77
var_dump($arr[0] + ($arr[0] = 2));
8+
9+
$obj = new stdClass;
10+
$obj->prop = 1;
11+
$ref =& $obj->prop;
12+
var_dump($obj->prop + ($obj->prop = 2));
13+
814
?>
915
--EXPECT--
10-
int(4)
16+
int(3)
17+
int(3)

Zend/zend_execute.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2033,7 +2033,9 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
20332033
ZEND_ASSERT(result != NULL);
20342034
if (retval) {
20352035
if (result != retval) {
2036-
ZVAL_COPY(result, retval);
2036+
ZVAL_COPY_DEREF(result, retval);
2037+
} else if (UNEXPECTED(Z_ISREF_P(retval))) {
2038+
zend_unwrap_reference(result);
20372039
}
20382040
} else {
20392041
ZVAL_NULL(result);

Zend/zend_types.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,12 +1123,11 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
11231123
efree_size(ref, sizeof(zend_reference)); \
11241124
} while (0)
11251125

1126-
#define ZVAL_COPY_UNREF(z, v) do { \
1126+
#define ZVAL_COPY_DEREF(z, v) do { \
11271127
zval *_z3 = (v); \
11281128
if (Z_OPT_REFCOUNTED_P(_z3)) { \
1129-
if (UNEXPECTED(Z_OPT_ISREF_P(_z3)) \
1130-
&& UNEXPECTED(Z_REFCOUNT_P(_z3) == 1)) { \
1131-
ZVAL_UNREF(_z3); \
1129+
if (UNEXPECTED(Z_OPT_ISREF_P(_z3))) { \
1130+
_z3 = Z_REFVAL_P(_z3); \
11321131
if (Z_OPT_REFCOUNTED_P(_z3)) { \
11331132
Z_ADDREF_P(_z3); \
11341133
} \

Zend/zend_vm_def.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ ZEND_VM_C_LABEL(fetch_this):
14541454

14551455
ZEND_ASSERT(retval != NULL);
14561456
if (type == BP_VAR_R || type == BP_VAR_IS) {
1457-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
1457+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
14581458
} else {
14591459
ZVAL_INDIRECT(EX_VAR(opline->result.var), retval);
14601460
}
@@ -1580,7 +1580,7 @@ ZEND_VM_HELPER(zend_fetch_static_prop_helper, CONST|TMPVAR|CV, UNUSED|CONST|VAR,
15801580
}
15811581

15821582
if (type == BP_VAR_R || type == BP_VAR_IS) {
1583-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
1583+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
15841584
} else {
15851585
ZVAL_INDIRECT(EX_VAR(opline->result.var), retval);
15861586
}
@@ -1634,7 +1634,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMP
16341634
ZEND_VM_C_LABEL(fetch_dim_r_array):
16351635
value = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, OP2_TYPE, BP_VAR_R EXECUTE_DATA_CC);
16361636
result = EX_VAR(opline->result.var);
1637-
ZVAL_COPY_UNREF(result, value);
1637+
ZVAL_COPY_DEREF(result, value);
16381638
} else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
16391639
container = Z_REFVAL_P(container);
16401640
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
@@ -1809,7 +1809,7 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST
18091809
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
18101810
retval = OBJ_PROP(zobj, prop_offset);
18111811
if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) {
1812-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
1812+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
18131813
break;
18141814
}
18151815
} else if (EXPECTED(zobj->properties != NULL)) {
@@ -1824,7 +1824,7 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST
18241824
(EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) &&
18251825
EXPECTED(p->key != NULL) &&
18261826
EXPECTED(zend_string_equal_content(p->key, Z_STR_P(offset)))))) {
1827-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), &p->val);
1827+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &p->val);
18281828
break;
18291829
}
18301830
}
@@ -1834,7 +1834,7 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST
18341834
if (EXPECTED(retval)) {
18351835
uintptr_t idx = (char*)retval - (char*)zobj->properties->arData;
18361836
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
1837-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
1837+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
18381838
break;
18391839
}
18401840
}
@@ -1851,7 +1851,9 @@ ZEND_VM_C_LABEL(fetch_obj_r_no_object):
18511851
retval = zobj->handlers->read_property(container, offset, BP_VAR_R, cache_slot, EX_VAR(opline->result.var));
18521852

18531853
if (retval != EX_VAR(opline->result.var)) {
1854-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
1854+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
1855+
} else if (UNEXPECTED(Z_ISREF_P(retval))) {
1856+
zend_unwrap_reference(retval);
18551857
}
18561858
}
18571859
} while (0);
@@ -8654,7 +8656,7 @@ ZEND_VM_C_LABEL(fetch_dim_r_index_array):
86548656
}
86558657
ht = Z_ARRVAL_P(container);
86568658
ZEND_HASH_INDEX_FIND(ht, offset, value, ZEND_VM_C_LABEL(fetch_dim_r_index_undef));
8657-
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), value);
8659+
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value);
86588660
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
86598661
SAVE_OPLINE();
86608662
FREE_OP1();

0 commit comments

Comments
 (0)