diff --git a/Zend/tests/compound_assign_failure.phpt b/Zend/tests/compound_assign_failure.phpt new file mode 100644 index 00000000000..f1afc783a0e --- /dev/null +++ b/Zend/tests/compound_assign_failure.phpt @@ -0,0 +1,24 @@ +--TEST-- +Behavior of failing compound assignment +--FILE-- +>= -1; +} catch (Error $e) { var_dump($a); } + +try { + $a = 1; + $a <<= -1; +} catch (Error $e) { var_dump($a); } +?> +--EXPECT-- +int(1) +int(1) +int(1) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index de0c19e94f1..d5d42ca1e14 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1182,10 +1182,6 @@ ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* { convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_MOD, mod_function); - if (op1 == result) { - zval_dtor(result); - } - if (op2_lval == 0) { /* modulus by zero */ if (EG(current_execute_data) && !CG(in_compilation)) { @@ -1193,10 +1189,16 @@ ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* { } else { zend_error_noreturn(E_ERROR, "Modulo by zero"); } - ZVAL_UNDEF(result); + if (op1 != result) { + ZVAL_UNDEF(result); + } return FAILURE; } + if (op1 == result) { + zval_dtor(result); + } + if (op2_lval == -1) { /* Prevent overflow error/crash if op1==LONG_MIN */ ZVAL_LONG(result, 0); @@ -1540,13 +1542,12 @@ ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SL, shift_left_function); - if (op1 == result) { - zval_dtor(result); - } - /* prevent wrapping quirkiness on some processors where << 64 + x == << x */ if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) { if (EXPECTED(op2_lval > 0)) { + if (op1 == result) { + zval_dtor(result); + } ZVAL_LONG(result, 0); return SUCCESS; } else { @@ -1555,11 +1556,17 @@ ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op } else { zend_error_noreturn(E_ERROR, "Bit shift by negative number"); } - ZVAL_UNDEF(result); + if (op1 != result) { + ZVAL_UNDEF(result); + } return FAILURE; } } + if (op1 == result) { + zval_dtor(result); + } + ZVAL_LONG(result, op1_lval << op2_lval); return SUCCESS; } @@ -1571,14 +1578,13 @@ ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *o convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SR, shift_right_function); - if (op1 == result) { - zval_dtor(result); - } - /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */ if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) { if (EXPECTED(op2_lval > 0)) { ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0); + if (op1 == result) { + zval_dtor(result); + } return SUCCESS; } else { if (EG(current_execute_data) && !CG(in_compilation)) { @@ -1586,11 +1592,17 @@ ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *o } else { zend_error_noreturn(E_ERROR, "Bit shift by negative number"); } - ZVAL_UNDEF(result); + if (op1 != result) { + ZVAL_UNDEF(result); + } return FAILURE; } } + if (op1 == result) { + zval_dtor(result); + } + ZVAL_LONG(result, op1_lval >> op2_lval); return SUCCESS; } @@ -1598,6 +1610,7 @@ ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *o ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */ { + zval *orig_op1 = op1; zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; @@ -1610,11 +1623,7 @@ ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) / ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function); use_copy1 = zend_make_printable_zval(op1, &op1_copy); if (use_copy1) { - /* We have created a converted copy of op1. Therefore, op1 won't become the result so - * we have to free it. - */ if (result == op1) { - zval_dtor(op1); if (UNEXPECTED(op1 == op2)) { op2 = &op1_copy; } @@ -1645,7 +1654,15 @@ ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) / if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { zend_throw_error(NULL, "String size overflow"); - ZVAL_FALSE(result); + if (UNEXPECTED(use_copy1)) { + zval_dtor(op1); + } + if (UNEXPECTED(use_copy2)) { + zval_dtor(op2); + } + if (orig_op1 != result) { + ZVAL_UNDEF(result); + } return FAILURE; } @@ -1655,6 +1672,9 @@ ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) / } else { result_str = zend_string_alloc(result_len, 0); memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len); + if (result == orig_op1) { + zval_dtor(orig_op1); + } } /* This has to happen first to account for the cases where result == op1 == op2 and