Skip to content

Commit bac5425

Browse files
committed
Correctly handle refs on ASSIGN_OBJ fastpath
1 parent b1df1b7 commit bac5425

File tree

3 files changed

+1077
-666
lines changed

3 files changed

+1077
-666
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
Refs on ASSIGN_OBJ fast-path
3+
--FILE--
4+
<?php
5+
6+
function &ref(&$foo) {
7+
return $foo;
8+
}
9+
10+
class Test {
11+
public array $prop;
12+
public int $prop2;
13+
14+
public function foo() {
15+
$array = [];
16+
$ref =& $array;
17+
$this->prop = $array;
18+
}
19+
20+
public function bar() {
21+
$str = "123";
22+
$this->prop2 = ref($str);
23+
}
24+
}
25+
26+
$test = new Test;
27+
$test->foo();
28+
$test->foo();
29+
$test->bar();
30+
$test->bar();
31+
var_dump($test);
32+
33+
?>
34+
--EXPECT--
35+
object(Test)#1 (2) {
36+
["prop"]=>
37+
array(0) {
38+
}
39+
["prop2"]=>
40+
int(123)
41+
}

Zend/zend_vm_def.h

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2331,23 +2331,43 @@ ZEND_VM_C_LABEL(assign_object):
23312331
zval tmp;
23322332

23332333
if (UNEXPECTED(prop_info != NULL)) {
2334-
ZVAL_COPY_VALUE(&tmp, value);
2334+
zend_reference *ref = NULL;
2335+
if ((OP_DATA_TYPE & (IS_CV|IS_VAR)) && UNEXPECTED(Z_ISREF_P(value))) {
2336+
ref = Z_REF_P(value);
2337+
value = Z_REFVAL_P(value);
2338+
}
2339+
if (((OP_DATA_TYPE & (IS_CONST|IS_CV)) || (ref && GC_REFCOUNT(ref) > 1))) {
2340+
ZVAL_COPY(&tmp, value);
2341+
} else {
2342+
ZVAL_COPY_VALUE(&tmp, value);
2343+
}
23352344
if (UNEXPECTED(!i_zend_verify_property_type(prop_info, &tmp, EX_USES_STRICT_TYPES()))) {
23362345
zend_verify_property_type_error(prop_info, value);
2337-
FREE_OP_DATA();
2346+
zval_ptr_dtor(value);
2347+
if ((OP_DATA_TYPE & IS_VAR) && ref && GC_DELREF(ref) == 0) {
2348+
efree(ref);
2349+
}
23382350
FREE_OP2();
23392351
FREE_OP1_VAR_PTR();
2352+
UNDEF_RESULT();
23402353
HANDLE_EXCEPTION();
23412354
}
2355+
23422356
/* will remain valid, thus no need to check prop_info in future here */
23432357
if (OP_DATA_TYPE == IS_CONST && Z_TYPE(tmp) == Z_TYPE_P(value)) {
23442358
CACHE_PTR_EX(cache_slot + 2, NULL);
23452359
}
2360+
23462361
value = &tmp;
2347-
}
2362+
if ((OP_DATA_TYPE & IS_VAR) && UNEXPECTED(ref) && GC_DELREF(ref) == 0) {
2363+
efree(ref);
2364+
}
23482365

2366+
value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES());
2367+
} else {
23492368
ZEND_VM_C_LABEL(fast_assign_obj):
2350-
value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
2369+
value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
2370+
}
23512371
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
23522372
ZVAL_COPY(EX_VAR(opline->result.var), value);
23532373
}
@@ -2427,11 +2447,8 @@ ZEND_VM_HANDLER(201, ZEND_ASSIGN_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CONST|VAR,
24272447
USE_OPLINE
24282448
zend_free_op free_op_data;
24292449
zval *prop, *value;
2430-
zend_reference *ref = NULL;
24312450
zend_property_info *prop_info;
2432-
#if !defined(ZEND_VM_SPEC) || !(OP_DATA_TYPE & IS_TMP_VAR)
24332451
zval tmp;
2434-
#endif
24352452

24362453
SAVE_OPLINE();
24372454

@@ -2444,22 +2461,17 @@ ZEND_VM_HANDLER(201, ZEND_ASSIGN_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CONST|VAR,
24442461
value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R);
24452462

24462463
if (UNEXPECTED(prop_info->type)) {
2447-
#if defined(ZEND_VM_SPEC) && (OP_DATA_TYPE & IS_TMP_VAR)
2448-
if (UNEXPECTED(!i_zend_verify_property_type(prop_info, value, EX_USES_STRICT_TYPES()))) {
2449-
#else
2450-
#if !defined(ZEND_VM_SPEC) || (OP_DATA_TYPE & (IS_CV | IS_VAR))
2451-
if (Z_ISREF_P(value)) {
2464+
zend_reference *ref = NULL;
2465+
if ((OP_DATA_TYPE & (IS_CV|IS_VAR)) && UNEXPECTED(Z_ISREF_P(value))) {
24522466
ref = Z_REF_P(value);
24532467
value = Z_REFVAL_P(value);
24542468
}
2455-
#endif
2456-
if (((OP_DATA_TYPE & (IS_CONST | IS_CV)) || (ref && GC_REFCOUNT(ref) > 1))) {
2469+
if (((OP_DATA_TYPE & (IS_CONST|IS_CV)) || (ref && GC_REFCOUNT(ref) > 1))) {
24572470
ZVAL_COPY(&tmp, value);
24582471
} else {
24592472
ZVAL_COPY_VALUE(&tmp, value);
24602473
}
24612474
if (UNEXPECTED(!i_zend_verify_property_type(prop_info, &tmp, EX_USES_STRICT_TYPES()))) {
2462-
#endif
24632475
zend_verify_property_type_error(prop_info, value);
24642476
zval_ptr_dtor(value);
24652477
if ((OP_DATA_TYPE & IS_VAR) && ref && GC_DELREF(ref) == 0) {
@@ -2468,13 +2480,11 @@ ZEND_VM_HANDLER(201, ZEND_ASSIGN_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CONST|VAR,
24682480
UNDEF_RESULT();
24692481
HANDLE_EXCEPTION();
24702482
}
2471-
#if !defined(ZEND_VM_SPEC) || !(OP_DATA_TYPE & IS_TMP_VAR)
2472-
value = &tmp;
24732483

2484+
value = &tmp;
24742485
if ((OP_DATA_TYPE & IS_VAR) && UNEXPECTED(ref) && GC_DELREF(ref) == 0) {
24752486
efree(ref);
24762487
}
2477-
#endif
24782488

24792489
value = zend_assign_to_variable(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES());
24802490
} else {

0 commit comments

Comments
 (0)