From cf377eefa66d76a83cf71dca9166015ccb97bb27 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 6 Dec 2021 21:56:04 +0100 Subject: [PATCH] Don't convert assign op operand types in opcache This is the same change as 56b18d478ed9e40afd66860e82017d5c2017eac1 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. --- Zend/Optimizer/pass1.c | 30 ++------------- Zend/tests/assign_op_type_error.phpt | 57 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 Zend/tests/assign_op_type_error.phpt diff --git a/Zend/Optimizer/pass1.c b/Zend/Optimizer/pass1.c index 110babf3e95..695348a3891 100644 --- a/Zend/Optimizer/pass1.c +++ b/Zend/Optimizer/pass1.c @@ -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; diff --git a/Zend/tests/assign_op_type_error.phpt b/Zend/tests/assign_op_type_error.phpt new file mode 100644 index 00000000000..5f175613e20 --- /dev/null +++ b/Zend/tests/assign_op_type_error.phpt @@ -0,0 +1,57 @@ +--TEST-- +TypeError for compound assignment operations +--FILE-- +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