Skip to content

Commit 05cb27a

Browse files
ext/bcmath: Check for scale overflow (#15741)
1 parent 00f0b80 commit 05cb27a

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ PHP NEWS
44

55
- BcMath:
66
. bcpow() performance improvement. (Jorg Sowa)
7+
. ext/bcmath: Check for scale overflow. (SakiTakamachi)
78

89
- Debugging:
910
. Fixed bug GH-15923 (GDB: Python Exception <class 'TypeError'>:

ext/bcmath/bcmath.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,7 @@ static int bcmath_number_compare(zval *op1, zval *op2);
802802
#else
803803
# define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX || scale < origin_scale)
804804
#endif
805+
#define CHECK_SCALE_OVERFLOW(scale) (scale > INT_MAX)
805806

806807
static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_obj(const zend_object *obj)
807808
{
@@ -1184,6 +1185,11 @@ static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zva
11841185
goto fail;
11851186
}
11861187

1188+
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
1189+
zend_value_error("scale must be between 0 and %d", INT_MAX);
1190+
goto fail;
1191+
}
1192+
11871193
bc_num ret = NULL;
11881194
size_t scale;
11891195
switch (opcode) {
@@ -1264,8 +1270,15 @@ static int bcmath_number_compare(zval *op1, zval *op2)
12641270
goto fallback;
12651271
}
12661272

1267-
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, NULL, obj1, str1, lval1) == FAILURE ||
1268-
bc_num_from_obj_or_str_or_long(&n2, NULL, obj2, str2, lval2) == FAILURE)) {
1273+
size_t n1_full_scale;
1274+
size_t n2_full_scale;
1275+
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE ||
1276+
bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
1277+
goto fallback;
1278+
}
1279+
1280+
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
1281+
zend_value_error("scale must be between 0 and %d", INT_MAX);
12691282
goto fallback;
12701283
}
12711284

@@ -1297,10 +1310,18 @@ static int bcmath_number_compare(zval *op1, zval *op2)
12971310
static zend_always_inline zend_result bc_num_from_obj_or_str_or_long_with_err(
12981311
bc_num *num, size_t *scale, zend_object *obj, zend_string *str, zend_long lval, uint32_t arg_num)
12991312
{
1300-
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, scale, obj, str, lval) == FAILURE)) {
1313+
size_t full_scale = 0;
1314+
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, &full_scale, obj, str, lval) == FAILURE)) {
13011315
zend_argument_value_error(arg_num, "is not well-formed");
13021316
return FAILURE;
13031317
}
1318+
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(full_scale))) {
1319+
zend_argument_value_error(arg_num, "must be between 0 and %d", INT_MAX);
1320+
return FAILURE;
1321+
}
1322+
if (scale != NULL) {
1323+
*scale = full_scale;
1324+
}
13041325
return SUCCESS;
13051326
}
13061327

@@ -1320,7 +1341,7 @@ PHP_METHOD(BcMath_Number, __construct)
13201341
}
13211342

13221343
bc_num num = NULL;
1323-
size_t scale;
1344+
size_t scale = 0;
13241345
if (bc_num_from_obj_or_str_or_long_with_err(&num, &scale, NULL, str, lval, 1) == FAILURE) {
13251346
bc_free_num(&num);
13261347
RETURN_THROWS();
@@ -1345,7 +1366,7 @@ static void bcmath_number_calc_method(INTERNAL_FUNCTION_PARAMETERS, uint8_t opco
13451366
ZEND_PARSE_PARAMETERS_END();
13461367

13471368
bc_num num = NULL;
1348-
size_t num_full_scale;
1369+
size_t num_full_scale = 0;
13491370
if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
13501371
goto fail;
13511372
}
@@ -1570,7 +1591,7 @@ PHP_METHOD(BcMath_Number, compare)
15701591
ZEND_PARSE_PARAMETERS_END();
15711592

15721593
bc_num num = NULL;
1573-
size_t num_full_scale;
1594+
size_t num_full_scale = 0;
15741595
if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
15751596
goto fail;
15761597
}
@@ -1704,8 +1725,8 @@ PHP_METHOD(BcMath_Number, __unserialize)
17041725
}
17051726

17061727
bc_num num = NULL;
1707-
size_t scale;
1708-
if (php_str2num_ex(&num, Z_STR_P(zv), &scale) == FAILURE) {
1728+
size_t scale = 0;
1729+
if (php_str2num_ex(&num, Z_STR_P(zv), &scale) == FAILURE || CHECK_SCALE_OVERFLOW(scale)) {
17091730
bc_free_num(&num);
17101731
goto fail;
17111732
}

0 commit comments

Comments
 (0)