diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index 202fe816568..94bba35a658 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -680,7 +680,13 @@ static inline int ct_eval_isset_isempty(zval *result, uint32_t extended_value, z } static inline void ct_eval_type_check(zval *result, uint32_t type_mask, zval *op1) { - ZVAL_BOOL(result, (type_mask >> Z_TYPE_P(op1)) & 1); + uint32_t type = Z_TYPE_P(op1); + if (type == PARTIAL_ARRAY) { + type = IS_ARRAY; + } else if (type == PARTIAL_OBJECT) { + type = IS_OBJECT; + } + ZVAL_BOOL(result, (type_mask >> type) & 1); } static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *op1, zval *op2) { @@ -1424,6 +1430,12 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); + /* TODO: We could implement support for evaluation of + on partial arrays. */ + if (IS_PARTIAL_ARRAY(op1) || IS_PARTIAL_ARRAY(op2)) { + SET_RESULT_BOT(result); + break; + } + if (zend_optimizer_eval_binary_op(&zv, opline->opcode, op1, op2) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); @@ -1610,6 +1622,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o case ZEND_BW_NOT: case ZEND_BOOL_NOT: SKIP_IF_TOP(op1); + if (IS_PARTIAL_ARRAY(op1)) { + SET_RESULT_BOT(result); + break; + } if (zend_optimizer_eval_unary_op(&zv, opline->opcode, op1) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); @@ -1619,6 +1635,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o break; case ZEND_CAST: SKIP_IF_TOP(op1); + if (IS_PARTIAL_ARRAY(op1)) { + SET_RESULT_BOT(result); + break; + } if (zend_optimizer_eval_cast(&zv, opline->extended_value, op1) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); @@ -1630,6 +1650,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: SKIP_IF_TOP(op1); + if (IS_PARTIAL_ARRAY(op1)) { + SET_RESULT_BOT(result); + break; + } ZVAL_BOOL(&zv, zend_is_true(op1)); SET_RESULT(result, &zv); break; @@ -1760,6 +1784,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o break; case ZEND_ROPE_INIT: SKIP_IF_TOP(op2); + if (IS_PARTIAL_ARRAY(op2)) { + SET_RESULT_BOT(result); + break; + } if (zend_optimizer_eval_cast(&zv, IS_STRING, op2) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); @@ -1774,6 +1802,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o // string for all SSA vars with some extra checks SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); + if (IS_PARTIAL_ARRAY(op2)) { + SET_RESULT_BOT(result); + break; + } if (zend_optimizer_eval_binary_op(&zv, ZEND_CONCAT, op1, op2) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); diff --git a/ext/opcache/tests/bug78015.phpt b/ext/opcache/tests/bug78015.phpt new file mode 100644 index 00000000000..a71626aa221 --- /dev/null +++ b/ext/opcache/tests/bug78015.phpt @@ -0,0 +1,70 @@ +--TEST-- +Bug #78015: Incorrect evaluation of expressions involving partials array in SCCP +--FILE-- + [$x], 'c' => [$x]]; + $d = $a['b'] + $a['c']; + return $d; +} + +function test2() { + global $x; + $a = ['b' => [$x]]; + $d = !$a['b']; + return $d; +} + +function test3() { + global $x; + $a = ['b' => [$x]]; + $d = (int) $a['b']; + return $d; +} + +function test4() { + global $x; + $a = ['b' => [$x]]; + $d = $a['b'] ?: 42; + return $d; +} + +function test5() { + global $x; + $a = ['b' => [$x]]; + $d = is_array($a['b']); + return $d; +} + +function test6() { + global $x; + $a = ['b' => [$x]]; + $b = "foo"; + $d = "$a[b]{$b}bar"; + return $d; +} + +var_dump(test1()); +var_dump(test2()); +var_dump(test3()); +var_dump(test4()); +var_dump(test5()); +var_dump(test6()); + +?> +--EXPECTF-- +array(1) { + [0]=> + int(1) +} +bool(false) +int(1) +int(42) +bool(true) + +Notice: Array to string conversion in %s on line %d +string(11) "Arrayfoobar"