From a983b728a787360ff033bbf79ec3bd538b6aafb0 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 5 Dec 2016 21:45:08 +0300 Subject: [PATCH] Fixed behavior of failing compound assignments (they shouldn't change the source value when exception thrown during type converion). --- Zend/tests/compound_assign_failure.phpt | 147 +++++++++++++++++++++++- Zend/zend_operators.c | 96 ++++++++++------ 2 files changed, 207 insertions(+), 36 deletions(-) diff --git a/Zend/tests/compound_assign_failure.phpt b/Zend/tests/compound_assign_failure.phpt index f8d863106a5..2e35ab4fff7 100644 --- a/Zend/tests/compound_assign_failure.phpt +++ b/Zend/tests/compound_assign_failure.phpt @@ -20,7 +20,7 @@ try { $a <<= -1; } catch (Error $e) { var_dump($a); } -set_error_handler(function() { throw new Exception; }); +set_error_handler(function($type, $msg) { throw new Exception($msg); }); try { $a = []; @@ -31,11 +31,154 @@ try { $a = "foo"; $a .= []; } catch (Throwable $e) { var_dump($a); } + +$x = new stdClass; +try { $x += 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x += new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x -= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x -= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x *= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x *= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x /= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x /= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x %= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x %= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x **= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x **= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x ^= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x ^= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x &= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x &= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x |= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x |= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x <<= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x <<= new stdClass; } +catch (Exception $e) {} +var_dump($x); + +$x = new stdClass; +try { $x >>= 1; } +catch (Exception $e) {} +var_dump($x); + +$x = 1; +try { $x >>= new stdClass; } +catch (Exception $e) {} +var_dump($x); ?> ---EXPECT-- +--EXPECTF-- int(1) int(1) int(1) array(0) { } string(3) "foo" +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) +object(stdClass)#%d (0) { +} +int(1) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index aa2aaf1ab1d..4798c7d2130 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -188,41 +188,45 @@ try_again: /* {{{ zendi_convert_scalar_to_number */ #define zendi_convert_scalar_to_number(op, holder, result) \ - if (op==result) { \ - if (Z_TYPE_P(op) != IS_LONG) { \ - convert_scalar_to_number(op); \ - } \ - } else { \ - switch (Z_TYPE_P(op)) { \ - case IS_STRING: \ - { \ + if (Z_TYPE_P(op) != IS_LONG) { \ + if (op==result && Z_TYPE_P(op) != IS_OBJECT) { \ + convert_scalar_to_number(op); \ + } else { \ + switch (Z_TYPE_P(op)) { \ + case IS_STRING: \ if ((Z_TYPE_INFO(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), 1)) == 0) { \ - ZVAL_LONG(&(holder), 0); \ - } \ - (op) = &(holder); \ - break; \ - } \ - case IS_NULL: \ - case IS_FALSE: \ - ZVAL_LONG(&(holder), 0); \ - (op) = &(holder); \ - break; \ - case IS_TRUE: \ - ZVAL_LONG(&(holder), 1); \ - (op) = &(holder); \ - break; \ - case IS_RESOURCE: \ - ZVAL_LONG(&(holder), Z_RES_HANDLE_P(op)); \ - (op) = &(holder); \ - break; \ - case IS_OBJECT: \ - ZVAL_COPY(&(holder), op); \ - convert_to_long_base(&(holder), 10); \ - if (Z_TYPE(holder) == IS_LONG) { \ - (op) = &(holder); \ - } \ - break; \ - } \ + ZVAL_LONG(&(holder), 0); \ + } \ + (op) = &(holder); \ + break; \ + case IS_NULL: \ + case IS_FALSE: \ + ZVAL_LONG(&(holder), 0); \ + (op) = &(holder); \ + break; \ + case IS_TRUE: \ + ZVAL_LONG(&(holder), 1); \ + (op) = &(holder); \ + break; \ + case IS_RESOURCE: \ + ZVAL_LONG(&(holder), Z_RES_HANDLE_P(op)); \ + (op) = &(holder); \ + break; \ + case IS_OBJECT: \ + ZVAL_COPY(&(holder), op); \ + convert_to_long_base(&(holder), 10); \ + if (UNEXPECTED(EG(exception))) { \ + return FAILURE; \ + } \ + if (Z_TYPE(holder) == IS_LONG) { \ + if (op == result) { \ + zval_ptr_dtor(op); \ + } \ + (op) = &(holder); \ + } \ + break; \ + } \ + } \ } /* }}} */ @@ -259,6 +263,9 @@ try_again: } \ ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(op, op_func); \ op1_lval = _zval_get_long_func(op1); \ + if (UNEXPECTED(EG(exception))) { \ + return FAILURE; \ + } \ } else { \ op1_lval = Z_LVAL_P(op1); \ } \ @@ -274,6 +281,9 @@ try_again: } \ ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(op); \ op2_lval = _zval_get_long_func(op2); \ + if (UNEXPECTED(EG(exception))) { \ + return FAILURE; \ + } \ } else { \ op2_lval = Z_LVAL_P(op2); \ } \ @@ -1383,12 +1393,18 @@ ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function); op1_lval = _zval_get_long_func(op1); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } } else { op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR); op2_lval = _zval_get_long_func(op2); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } } else { op2_lval = Z_LVAL_P(op2); } @@ -1453,12 +1469,18 @@ ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *o if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_and_function); op1_lval = _zval_get_long_func(op1); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } } else { op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND); op2_lval = _zval_get_long_func(op2); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } } else { op2_lval = Z_LVAL_P(op2); } @@ -1523,12 +1545,18 @@ ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *o if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_xor_function); op1_lval = _zval_get_long_func(op1); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } } else { op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR); op2_lval = _zval_get_long_func(op2); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } } else { op2_lval = Z_LVAL_P(op2); }