Skip to content

Commit 4f5a6a3

Browse files
committed
Fix RC tracking of op1 of FETCH_OBJ
Fixes GH-17151
1 parent 07cd468 commit 4f5a6a3

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

Zend/Optimizer/zend_inference.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3767,6 +3767,36 @@ static zend_always_inline zend_result _zend_update_type_info(
37673767
case ZEND_FETCH_OBJ_W:
37683768
case ZEND_FETCH_OBJ_UNSET:
37693769
case ZEND_FETCH_OBJ_FUNC_ARG:
3770+
if (ssa_op->op1_def >= 0) {
3771+
tmp = t1;
3772+
if (tmp & (MAY_BE_RC1|MAY_BE_RCN)) {
3773+
do {
3774+
const zend_class_entry *ce = NULL;
3775+
3776+
if (opline->op1_type == IS_UNUSED) {
3777+
ce = op_array->scope;
3778+
} else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) {
3779+
ce = ssa->var_info[ssa_op->op1_use].ce;
3780+
}
3781+
3782+
// FIXME: Could be more permissive by checking for corresponding bp type,
3783+
// handler, hook and magic method.
3784+
if (ce
3785+
&& !ce->create_object
3786+
&& ce->default_object_handlers == &std_object_handlers) {
3787+
const zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
3788+
if ((prop_info && !prop_info->hooks)
3789+
|| (!ce->__get && !ce->__set && !ce->__isset && !ce->__unset)) {
3790+
break;
3791+
}
3792+
}
3793+
3794+
tmp |= (MAY_BE_RC1|MAY_BE_RCN);
3795+
} while (0);
3796+
}
3797+
UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3798+
COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3799+
}
37703800
if (ssa_op->result_def >= 0) {
37713801
uint32_t tmp = 0;
37723802
ce = NULL;

Zend/Optimizer/zend_ssa.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,18 @@ static zend_always_inline int _zend_ssa_rename_op(const zend_op_array *op_array,
794794
}
795795
}
796796
}
797+
break;
797798
}
799+
case ZEND_FETCH_OBJ_R:
800+
case ZEND_FETCH_OBJ_IS:
801+
case ZEND_FETCH_OBJ_RW:
802+
case ZEND_FETCH_OBJ_W:
803+
case ZEND_FETCH_OBJ_UNSET:
804+
case ZEND_FETCH_OBJ_FUNC_ARG:
805+
if ((build_flags & ZEND_SSA_RC_INFERENCE) && (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR))) {
806+
goto add_op1_def;
807+
}
808+
break;
798809
default:
799810
break;
800811
}

ext/opcache/jit/zend_jit_ir.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14591,6 +14591,9 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
1459114591
if (on_this) {
1459214592
op1_info &= ~MAY_BE_RC1;
1459314593
}
14594+
if (ssa_op->op1_def >= 0) {
14595+
op1_info |= (ssa->var_info[ssa_op->op1_def].type & (MAY_BE_RC1|MAY_BE_RCN));
14596+
}
1459414597
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
1459514598
}
1459614599
}

ext/opcache/tests/jit/gh17151_1.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-17151: ZEND_FETCH_OBJ_R may modify RC of op1
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public function __get($name) {
8+
return $this;
9+
}
10+
}
11+
12+
function test() {
13+
$x = (new C)->bar;
14+
var_dump($x);
15+
}
16+
17+
test();
18+
19+
?>
20+
--EXPECTF--
21+
object(C)#%d (0) {
22+
}

ext/opcache/tests/jit/gh17151_2.phpt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GH-17151: ZEND_FETCH_OBJ_R may modify RC of op1
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public static $prop;
8+
9+
public function __get($name) {
10+
C::$prop = null;
11+
}
12+
13+
public function __destruct() {
14+
echo __METHOD__, "\n";
15+
}
16+
}
17+
18+
function test() {
19+
C::$prop = new C();
20+
C::$prop->bar;
21+
}
22+
23+
test();
24+
echo "Done\n";
25+
26+
?>
27+
--EXPECT--
28+
C::__destruct
29+
Done

0 commit comments

Comments
 (0)