diff options
-rw-r--r-- | Zend/tests/add_002.phpt | 4 | ||||
-rw-r--r-- | Zend/tests/add_007.phpt | 4 | ||||
-rw-r--r-- | Zend/tests/compound_assign_failure.phpt | 10 | ||||
-rw-r--r-- | Zend/zend_operators.c | 584 |
4 files changed, 293 insertions, 309 deletions
diff --git a/Zend/tests/add_002.phpt b/Zend/tests/add_002.phpt index 5d862ef729..da99499864 100644 --- a/Zend/tests/add_002.phpt +++ b/Zend/tests/add_002.phpt @@ -20,12 +20,8 @@ var_dump($c); echo "Done\n"; ?> --EXPECTF-- -Notice: Object of class stdClass could not be converted to number in %sadd_002.php on line %d - Exception: Unsupported operand types -Notice: Object of class stdClass could not be converted to number in %s on line %d - Fatal error: Uncaught Error: Unsupported operand types in %s:%d Stack trace: #0 {main} diff --git a/Zend/tests/add_007.phpt b/Zend/tests/add_007.phpt index e490826d8f..e7e0de79ba 100644 --- a/Zend/tests/add_007.phpt +++ b/Zend/tests/add_007.phpt @@ -19,12 +19,8 @@ var_dump($c); echo "Done\n"; ?> --EXPECTF-- -Warning: A non-numeric value encountered in %s on line %d - Exception: Unsupported operand types -Warning: A non-numeric value encountered in %s on line %d - Fatal error: Uncaught Error: Unsupported operand types in %s:%d Stack trace: #0 {main} diff --git a/Zend/tests/compound_assign_failure.phpt b/Zend/tests/compound_assign_failure.phpt index b4563e341f..1780725d93 100644 --- a/Zend/tests/compound_assign_failure.phpt +++ b/Zend/tests/compound_assign_failure.phpt @@ -208,19 +208,19 @@ string(3) "foo" object(stdClass)#%d (0) { } int(1) -int(0) +string(3) "foo" object(stdClass)#%d (0) { } int(1) -int(0) +string(3) "foo" object(stdClass)#%d (0) { } int(1) -int(0) +string(3) "foo" object(stdClass)#%d (0) { } int(1) -int(0) +string(3) "foo" object(stdClass)#%d (0) { } int(1) @@ -228,7 +228,7 @@ string(3) "foo" object(stdClass)#%d (0) { } int(1) -int(0) +string(3) "foo" object(stdClass)#%d (0) { } int(1) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 54298a00a9..af21693f3b 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -145,7 +145,7 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* { /* }}} */ -static void ZEND_FASTCALL _convert_scalar_to_number(zval *op, zend_bool silent, zend_bool check) /* {{{ */ +ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */ { try_again: switch (Z_TYPE_P(op)) { @@ -157,11 +157,8 @@ try_again: zend_string *str; str = Z_STR_P(op); - if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), silent ? 1 : -1)) == 0) { + if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) { ZVAL_LONG(op, 0); - if (!silent) { - zend_error(E_WARNING, "A non-numeric value encountered"); - } } zend_string_release_ex(str, 0); break; @@ -185,9 +182,6 @@ try_again: zval dst; convert_object_to_type(op, &dst, _IS_NUMBER); - if (check && UNEXPECTED(EG(exception))) { - return; - } zval_ptr_dtor(op); if (Z_TYPE(dst) == IS_LONG || Z_TYPE(dst) == IS_DOUBLE) { @@ -201,14 +195,8 @@ try_again: } /* }}} */ -ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */ -{ - _convert_scalar_to_number(op, 1, 0); -} -/* }}} */ - -/* {{{ _zendi_convert_scalar_to_number_ex */ -static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zval *holder, zend_bool silent) /* {{{ */ +/* {{{ _zendi_convert_scalar_to_number */ +static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_silent(zval *op, zval *holder) /* {{{ */ { switch (Z_TYPE_P(op)) { case IS_NULL: @@ -219,11 +207,8 @@ static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zva ZVAL_LONG(holder, 1); return holder; case IS_STRING: - if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), silent ? 1 : -1)) == 0) { + if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), 1)) == 0) { ZVAL_LONG(holder, 0); - if (!silent) { - zend_error(E_WARNING, "A non-numeric value encountered"); - } } return holder; case IS_RESOURCE: @@ -244,25 +229,52 @@ static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zva } /* }}} */ -/* {{{ _zendi_convert_scalar_to_number */ -static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_silent(zval *op, zval *holder) /* {{{ */ +static zend_never_inline int ZEND_FASTCALL _zendi_try_convert_scalar_to_number(zval *op, zval *holder) /* {{{ */ { - return _zendi_convert_scalar_to_number_ex(op, holder, 1); + switch (Z_TYPE_P(op)) { + case IS_NULL: + case IS_FALSE: + ZVAL_LONG(holder, 0); + return SUCCESS; + case IS_TRUE: + ZVAL_LONG(holder, 1); + return SUCCESS; + case IS_STRING: + if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), -1)) == 0) { + ZVAL_LONG(holder, 0); + zend_error(E_WARNING, "A non-numeric value encountered"); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } + } + return SUCCESS; + case IS_RESOURCE: + ZVAL_LONG(holder, Z_RES_HANDLE_P(op)); + return SUCCESS; + case IS_OBJECT: + convert_object_to_type(op, holder, _IS_NUMBER); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } + if (UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) { + ZVAL_LONG(holder, 1); + } + return SUCCESS; + default: + return FAILURE; + } } /* }}} */ -/* {{{ _zendi_convert_scalar_to_number_noisy */ -static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_noisy(zval *op, zval *holder) /* {{{ */ +static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval *holder) { - return _zendi_convert_scalar_to_number_ex(op, holder, 0); + if (Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_DOUBLE) { + ZVAL_COPY_VALUE(holder, op); + return SUCCESS; + } else { + return _zendi_try_convert_scalar_to_number(op, holder); + } } -/* }}} */ - -#define zendi_convert_scalar_to_number_noisy(op, holder, result) \ - ((Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_DOUBLE) ? (op) : \ - (((op) == result) \ - ? (_convert_scalar_to_number((op), /* silent */ 0, 1), (op)) : \ - _zendi_convert_scalar_to_number_noisy((op), holder))) #define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, op, op_func) \ do { \ @@ -941,42 +953,35 @@ static zend_always_inline int add_function_fast(zval *result, zval *op1, zval *o static zend_never_inline int ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */ { - zval op1_copy, op2_copy; - int converted = 0; + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (add_function_fast(result, op1, op2) == SUCCESS) { + return SUCCESS; + } - while (1) { - if (Z_ISREF_P(op1)) { - op1 = Z_REFVAL_P(op1); - } else if (Z_ISREF_P(op2)) { - op2 = Z_REFVAL_P(op2); - } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function); - - if (EXPECTED(op1 != op2)) { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result); - } else { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = op1; - } - if (EG(exception)) { - if (result != op1) { - ZVAL_UNDEF(result); - } - return FAILURE; - } - converted = 1; - } else { - if (result != op1) { - ZVAL_UNDEF(result); - } + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function); + + zval op1_copy, op2_copy; + if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE) + || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) { + if (!EG(exception)) { zend_throw_error(NULL, "Unsupported operand types"); - return FAILURE; /* unknown datatype */ } - if (add_function_fast(result, op1, op2) == SUCCESS) { - return SUCCESS; + if (result != op1) { + ZVAL_UNDEF(result); } + return FAILURE; } + + if (result == op1) { + zval_ptr_dtor(result); + } + + if (add_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) { + return SUCCESS; + } + + ZEND_ASSERT(0 && "Operation must succeed"); } /* }}} */ ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */ @@ -1013,42 +1018,35 @@ static zend_always_inline int sub_function_fast(zval *result, zval *op1, zval *o static zend_never_inline int ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */ { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (sub_function_fast(result, op1, op2) == SUCCESS) { + return SUCCESS; + } + + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function); + zval op1_copy, op2_copy; - int converted = 0; - while (1) { - if (Z_ISREF_P(op1)) { - op1 = Z_REFVAL_P(op1); - } else if (Z_ISREF_P(op2)) { - op2 = Z_REFVAL_P(op2); - } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function); - - if (EXPECTED(op1 != op2)) { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result); - } else { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = op1; - } - if (EG(exception)) { - if (result != op1) { - ZVAL_UNDEF(result); - } - return FAILURE; - } - converted = 1; - } else { - if (result != op1) { - ZVAL_UNDEF(result); - } + if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE) + || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) { + if (!EG(exception)) { zend_throw_error(NULL, "Unsupported operand types"); - return FAILURE; /* unknown datatype */ } - if (sub_function_fast(result, op1, op2) == SUCCESS) { - return SUCCESS; + if (result != op1) { + ZVAL_UNDEF(result); } + return FAILURE; } + if (result == op1) { + zval_ptr_dtor(result); + } + + if (sub_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) { + return SUCCESS; + } + + ZEND_ASSERT(0 && "Operation must succeed"); } /* }}} */ @@ -1062,249 +1060,243 @@ ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* { } /* }}} */ -ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */ +static zend_always_inline int mul_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */ { - zval op1_copy, op2_copy; - int converted = 0; + zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); - while (1) { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { + zend_long overflow; + ZEND_SIGNED_MULTIPLY_LONG( + Z_LVAL_P(op1), Z_LVAL_P(op2), + Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) { + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) { + ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2)); + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) { + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2))); + return SUCCESS; + } else { + return FAILURE; + } +} - if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { - zend_long overflow; +static zend_never_inline int ZEND_FASTCALL mul_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */ +{ + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (mul_function_fast(result, op1, op2) == SUCCESS) { + return SUCCESS; + } - ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow); - Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; - return SUCCESS; + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function); - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); - return SUCCESS; + zval op1_copy, op2_copy; + if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE) + || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) { + if (!EG(exception)) { + zend_throw_error(NULL, "Unsupported operand types"); + } + if (result != op1) { + ZVAL_UNDEF(result); + } + return FAILURE; + } - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) { - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2)); - return SUCCESS; + if (result == op1) { + zval_ptr_dtor(result); + } - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2))); - return SUCCESS; + if (mul_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) { + return SUCCESS; + } - } else { - if (Z_ISREF_P(op1)) { - op1 = Z_REFVAL_P(op1); - } else if (Z_ISREF_P(op2)) { - op2 = Z_REFVAL_P(op2); - } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function); + ZEND_ASSERT(0 && "Operation must succeed"); +} +/* }}} */ - if (EXPECTED(op1 != op2)) { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result); - } else { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = op1; - } - if (EG(exception)) { - if (result != op1) { - ZVAL_UNDEF(result); - } - return FAILURE; - } - converted = 1; - } else { - if (result != op1) { - ZVAL_UNDEF(result); - } - zend_throw_error(NULL, "Unsupported operand types"); - return FAILURE; /* unknown datatype */ - } - } +ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */ +{ + if (mul_function_fast(result, op1, op2) == SUCCESS) { + return SUCCESS; + } else { + return mul_function_slow(result, op1, op2); } } /* }}} */ -ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */ +static int ZEND_FASTCALL pow_function_base(zval *result, zval *op1, zval *op2) /* {{{ */ { - zval op1_copy, op2_copy; - int converted = 0; - - while (1) { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); - - if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { - if (Z_LVAL_P(op2) >= 0) { - zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2); - - if (i == 0) { - ZVAL_LONG(result, 1L); - return SUCCESS; - } else if (l2 == 0) { - ZVAL_LONG(result, 0); - return SUCCESS; - } + zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); - while (i >= 1) { - zend_long overflow; - double dval = 0.0; + if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { + if (Z_LVAL_P(op2) >= 0) { + zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2); - if (i % 2) { - --i; - ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow); - if (overflow) { - ZVAL_DOUBLE(result, dval * pow(l2, i)); - return SUCCESS; - } - } else { - i /= 2; - ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow); - if (overflow) { - ZVAL_DOUBLE(result, (double)l1 * pow(dval, i)); - return SUCCESS; - } - } - } - /* i == 0 */ - ZVAL_LONG(result, l1); - } else { - ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2))); + if (i == 0) { + ZVAL_LONG(result, 1L); + return SUCCESS; + } else if (l2 == 0) { + ZVAL_LONG(result, 0); + return SUCCESS; } - return SUCCESS; - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) { - ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2))); - return SUCCESS; + while (i >= 1) { + zend_long overflow; + double dval = 0.0; - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) { - ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2))); - return SUCCESS; - - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) { - ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2))); - return SUCCESS; - - } else { - if (Z_ISREF_P(op1)) { - op1 = Z_REFVAL_P(op1); - } else if (Z_ISREF_P(op2)) { - op2 = Z_REFVAL_P(op2); - } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function); - - if (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY) { - if (result != op1) { - ZVAL_UNDEF(result); + if (i % 2) { + --i; + ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow); + if (overflow) { + ZVAL_DOUBLE(result, dval * pow(l2, i)); + return SUCCESS; } - zend_throw_error(NULL, "Unsupported operand types"); - return FAILURE; - } - - if (EXPECTED(op1 != op2)) { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result); } else { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = op1; - } - - if (EG(exception)) { - if (result != op1) { - ZVAL_UNDEF(result); + i /= 2; + ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow); + if (overflow) { + ZVAL_DOUBLE(result, (double)l1 * pow(dval, i)); + return SUCCESS; } - return FAILURE; } - converted = 1; - } else { - if (result != op1) { - ZVAL_UNDEF(result); - } - zend_throw_error(NULL, "Unsupported operand types"); - return FAILURE; } + /* i == 0 */ + ZVAL_LONG(result, l1); + } else { + ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2))); } + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) { + ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2))); + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) { + ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2))); + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) { + ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2))); + return SUCCESS; + } else { + return FAILURE; } } /* }}} */ -#ifdef __clang__ -__attribute__((no_sanitize("float-divide-by-zero"))) -#endif -ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */ +ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */ { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (pow_function_base(result, op1, op2) == SUCCESS) { + return SUCCESS; + } + + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function); + zval op1_copy, op2_copy; - int converted = 0; + if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE) + || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) { + if (!EG(exception)) { + zend_throw_error(NULL, "Unsupported operand types"); + } + if (result != op1) { + ZVAL_UNDEF(result); + } + return FAILURE; + } - while (1) { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + if (result == op1) { + zval_ptr_dtor(result); + } - if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { - if (Z_LVAL_P(op2) == 0) { - zend_error(E_WARNING, "Division by zero"); - ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2))); - return SUCCESS; - } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) { - /* Prevent overflow error/crash */ - ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1); - return SUCCESS; - } - if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */ - ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2)); - } else { - ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2)); - } - return SUCCESS; + if (pow_function_base(result, &op1_copy, &op2_copy) == SUCCESS) { + return SUCCESS; + } - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) { - if (Z_DVAL_P(op2) == 0) { - zend_error(E_WARNING, "Division by zero"); - } - ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2)); - return SUCCESS; + ZEND_ASSERT(0 && "Operation must succeed"); +} +/* }}} */ - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) { - if (Z_LVAL_P(op2) == 0) { - zend_error(E_WARNING, "Division by zero"); - } - ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2)); - return SUCCESS; +#ifdef __clang__ +__attribute__((no_sanitize("float-divide-by-zero"))) +#endif +static int ZEND_FASTCALL div_function_base(zval *result, zval *op1, zval *op2) /* {{{ */ +{ + zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); - } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) { - if (Z_DVAL_P(op2) == 0) { - zend_error(E_WARNING, "Division by zero"); - } - ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2)); + if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { + if (Z_LVAL_P(op2) == 0) { + zend_error(E_WARNING, "Division by zero"); + ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2))); return SUCCESS; - + } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) { + /* Prevent overflow error/crash */ + ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1); + return SUCCESS; + } + if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */ + ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2)); } else { - if (Z_ISREF_P(op1)) { - op1 = Z_REFVAL_P(op1); - } else if (Z_ISREF_P(op2)) { - op2 = Z_REFVAL_P(op2); - } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function); + ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2)); + } + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) { + if (Z_DVAL_P(op2) == 0) { + zend_error(E_WARNING, "Division by zero"); + } + ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2)); + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) { + if (Z_LVAL_P(op2) == 0) { + zend_error(E_WARNING, "Division by zero"); + } + ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2)); + return SUCCESS; + } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) { + if (Z_DVAL_P(op2) == 0) { + zend_error(E_WARNING, "Division by zero"); + } + ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2)); + return SUCCESS; + } else { + return FAILURE; + } +} - if (EXPECTED(op1 != op2)) { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result); - } else { - op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result); - op2 = op1; - } - if (EG(exception)) { - if (result != op1) { - ZVAL_UNDEF(result); - } - return FAILURE; - } - converted = 1; - } else { - if (result != op1) { - ZVAL_UNDEF(result); - } - zend_throw_error(NULL, "Unsupported operand types"); - return FAILURE; /* unknown datatype */ - } +ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */ +{ + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (div_function_base(result, op1, op2) == SUCCESS) { + return SUCCESS; + } + + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function); + + zval op1_copy, op2_copy; + if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE) + || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) { + if (!EG(exception)) { + zend_throw_error(NULL, "Unsupported operand types"); } + if (result != op1) { + ZVAL_UNDEF(result); + } + return FAILURE; + } + + if (result == op1) { + zval_ptr_dtor(result); } + + if (div_function_base(result, &op1_copy, &op2_copy) == SUCCESS) { + return SUCCESS; + } + + ZEND_ASSERT(0 && "Operation must succeed"); } /* }}} */ |