Don't convert assign op operand types in opcache

This is the same change as 56b18d478e
but for ASSIGN_OP. Changing the operand type may change the error
message and can result in different behavior with operator overloading.

As with the other patch, if there is strong interest this could be
added to the DFA pass instead, with an appropriate type check.
This commit is contained in:
Nikita Popov 2021-12-06 21:56:04 +01:00
parent 6f325104eb
commit cf377eefa6
2 changed files with 60 additions and 27 deletions

View File

@ -104,33 +104,9 @@ constant_binary_op:
break;
case ZEND_ASSIGN_OP:
if (opline->op2_type == IS_CONST) {
if (opline->extended_value == ZEND_ADD
|| opline->extended_value == ZEND_SUB
|| opline->extended_value == ZEND_MUL
|| opline->extended_value == ZEND_DIV
|| opline->extended_value == ZEND_POW) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
/* don't optimize if it should produce a runtime numeric string error */
if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
}
}
} else if (opline->extended_value == ZEND_MOD
|| opline->extended_value == ZEND_SL
|| opline->extended_value == ZEND_SR) {
zval *op2 = &ZEND_OP2_LITERAL(opline);
if (Z_TYPE_P(op2) != IS_LONG) {
if (!zend_is_op_long_compatible(op2)) {
break;
}
convert_to_long(op2);
}
} else if (opline->extended_value == ZEND_CONCAT) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
convert_to_string(&ZEND_OP2_LITERAL(opline));
}
}
if (opline->extended_value == ZEND_CONCAT && opline->op2_type == IS_CONST
&& Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
convert_to_string(&ZEND_OP2_LITERAL(opline));
}
break;

View File

@ -0,0 +1,57 @@
--TEST--
TypeError for compound assignment operations
--FILE--
<?php
$x = [];
try {
$x += "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x -= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x *= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x /= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x **= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x %= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x <<= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$x >>= "1";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
Unsupported operand types: array + string
Unsupported operand types: array - string
Unsupported operand types: array * string
Unsupported operand types: array / string
Unsupported operand types: array ** string
Unsupported operand types: array % string
Unsupported operand types: array << string
Unsupported operand types: array >> string