ext/bcmath: Check for scale overflow (#15741)

This commit is contained in:
Saki Takamachi 2024-09-22 06:59:06 +09:00 committed by GitHub
parent 00f0b80189
commit 05cb27a8f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 30 additions and 8 deletions

1
NEWS
View file

@ -4,6 +4,7 @@ PHP NEWS
- BcMath: - BcMath:
. bcpow() performance improvement. (Jorg Sowa) . bcpow() performance improvement. (Jorg Sowa)
. ext/bcmath: Check for scale overflow. (SakiTakamachi)
- Debugging: - Debugging:
. Fixed bug GH-15923 (GDB: Python Exception <class 'TypeError'>: . Fixed bug GH-15923 (GDB: Python Exception <class 'TypeError'>:

View file

@ -802,6 +802,7 @@ static int bcmath_number_compare(zval *op1, zval *op2);
#else #else
# define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX || scale < origin_scale) # define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX || scale < origin_scale)
#endif #endif
#define CHECK_SCALE_OVERFLOW(scale) (scale > INT_MAX)
static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_obj(const zend_object *obj) static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_obj(const zend_object *obj)
{ {
@ -1184,6 +1185,11 @@ static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zva
goto fail; goto fail;
} }
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
zend_value_error("scale must be between 0 and %d", INT_MAX);
goto fail;
}
bc_num ret = NULL; bc_num ret = NULL;
size_t scale; size_t scale;
switch (opcode) { switch (opcode) {
@ -1264,8 +1270,15 @@ static int bcmath_number_compare(zval *op1, zval *op2)
goto fallback; goto fallback;
} }
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, NULL, obj1, str1, lval1) == FAILURE || size_t n1_full_scale;
bc_num_from_obj_or_str_or_long(&n2, NULL, obj2, str2, lval2) == FAILURE)) { size_t n2_full_scale;
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE ||
bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
goto fallback;
}
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
zend_value_error("scale must be between 0 and %d", INT_MAX);
goto fallback; goto fallback;
} }
@ -1297,10 +1310,18 @@ fallback:
static zend_always_inline zend_result bc_num_from_obj_or_str_or_long_with_err( static zend_always_inline zend_result bc_num_from_obj_or_str_or_long_with_err(
bc_num *num, size_t *scale, zend_object *obj, zend_string *str, zend_long lval, uint32_t arg_num) bc_num *num, size_t *scale, zend_object *obj, zend_string *str, zend_long lval, uint32_t arg_num)
{ {
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, scale, obj, str, lval) == FAILURE)) { size_t full_scale = 0;
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, &full_scale, obj, str, lval) == FAILURE)) {
zend_argument_value_error(arg_num, "is not well-formed"); zend_argument_value_error(arg_num, "is not well-formed");
return FAILURE; return FAILURE;
} }
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(full_scale))) {
zend_argument_value_error(arg_num, "must be between 0 and %d", INT_MAX);
return FAILURE;
}
if (scale != NULL) {
*scale = full_scale;
}
return SUCCESS; return SUCCESS;
} }
@ -1320,7 +1341,7 @@ PHP_METHOD(BcMath_Number, __construct)
} }
bc_num num = NULL; bc_num num = NULL;
size_t scale; size_t scale = 0;
if (bc_num_from_obj_or_str_or_long_with_err(&num, &scale, NULL, str, lval, 1) == FAILURE) { if (bc_num_from_obj_or_str_or_long_with_err(&num, &scale, NULL, str, lval, 1) == FAILURE) {
bc_free_num(&num); bc_free_num(&num);
RETURN_THROWS(); RETURN_THROWS();
@ -1345,7 +1366,7 @@ static void bcmath_number_calc_method(INTERNAL_FUNCTION_PARAMETERS, uint8_t opco
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
bc_num num = NULL; bc_num num = NULL;
size_t num_full_scale; size_t num_full_scale = 0;
if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) { if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
goto fail; goto fail;
} }
@ -1570,7 +1591,7 @@ PHP_METHOD(BcMath_Number, compare)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
bc_num num = NULL; bc_num num = NULL;
size_t num_full_scale; size_t num_full_scale = 0;
if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) { if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
goto fail; goto fail;
} }
@ -1704,8 +1725,8 @@ PHP_METHOD(BcMath_Number, __unserialize)
} }
bc_num num = NULL; bc_num num = NULL;
size_t scale; size_t scale = 0;
if (php_str2num_ex(&num, Z_STR_P(zv), &scale) == FAILURE) { if (php_str2num_ex(&num, Z_STR_P(zv), &scale) == FAILURE || CHECK_SCALE_OVERFLOW(scale)) {
bc_free_num(&num); bc_free_num(&num);
goto fail; goto fail;
} }