Skip to content

Commit 0d2d353

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: ext/bcmath: bounds-check $precision in bcround() and Number::round() (#22182)
2 parents d89f14b + 16e217e commit 0d2d353

3 files changed

Lines changed: 50 additions & 6 deletions

File tree

ext/bcmath/bcmath.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ static zend_always_inline zend_result bcmath_check_scale(zend_long scale, uint32
155155
return SUCCESS;
156156
}
157157

158+
static zend_result bcmath_check_precision(zend_long precision, uint32_t arg_num)
159+
{
160+
if (ZEND_LONG_INT_OVFL(precision)) {
161+
zend_argument_value_error(arg_num, "must be between " ZEND_LONG_FMT " and %d",
162+
(zend_long) ZEND_LONG_MIN, INT_MAX);
163+
return FAILURE;
164+
}
165+
return SUCCESS;
166+
}
167+
158168
static void php_long2num(bc_num *num, zend_long lval)
159169
{
160170
*num = bc_long2num(lval);
@@ -795,6 +805,10 @@ PHP_FUNCTION(bcround)
795805
Z_PARAM_ENUM(rounding_mode, rounding_mode_ce)
796806
ZEND_PARSE_PARAMETERS_END();
797807

808+
if (bcmath_check_precision(precision, 2) == FAILURE) {
809+
RETURN_THROWS();
810+
}
811+
798812
switch (rounding_mode) {
799813
case ZEND_ENUM_RoundingMode_HalfAwayFromZero:
800814
case ZEND_ENUM_RoundingMode_HalfTowardsZero:
@@ -1794,6 +1808,10 @@ PHP_METHOD(BcMath_Number, round)
17941808
Z_PARAM_ENUM(rounding_mode, rounding_mode_ce);
17951809
ZEND_PARSE_PARAMETERS_END();
17961810

1811+
if (bcmath_check_precision(precision, 1) == FAILURE) {
1812+
RETURN_THROWS();
1813+
}
1814+
17971815
switch (rounding_mode) {
17981816
case ZEND_ENUM_RoundingMode_HalfAwayFromZero:
17991817
case ZEND_ENUM_RoundingMode_HalfTowardsZero:

ext/bcmath/libbcmath/src/round.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,10 @@ size_t bc_round(bc_num num, zend_long precision, zend_enum_RoundingMode mode, bc
6767
return 0;
6868
}
6969

70-
/* If precision is -3, it becomes 1000. */
71-
if (UNEXPECTED(precision == ZEND_LONG_MIN)) {
72-
*result = bc_new_num((size_t) ZEND_LONG_MAX + 2, 0);
73-
} else {
74-
*result = bc_new_num(-precision + 1, 0);
75-
}
70+
/* If precision is -3, it becomes 1000. Negate in unsigned space so
71+
* precision == ZEND_LONG_MIN doesn't overflow signed long. */
72+
zend_ulong magnitude = -(zend_ulong) precision;
73+
*result = bc_new_num((size_t) magnitude + 1, 0);
7674
(*result)->n_value[0] = 1;
7775
(*result)->n_sign = num->n_sign;
7876
return 0;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
bcround() and BcMath\Number::round() reject $precision above INT_MAX
3+
--EXTENSIONS--
4+
bcmath
5+
--SKIPIF--
6+
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
7+
--FILE--
8+
<?php
9+
try {
10+
bcround('1', PHP_INT_MAX);
11+
} catch (\ValueError $e) {
12+
echo $e->getMessage() . \PHP_EOL;
13+
}
14+
try {
15+
(new BcMath\Number('1'))->round(PHP_INT_MAX);
16+
} catch (\ValueError $e) {
17+
echo $e->getMessage() . \PHP_EOL;
18+
}
19+
try {
20+
(new BcMath\Number('1'))->round(2147483648); // INT_MAX + 1
21+
} catch (\ValueError $e) {
22+
echo $e->getMessage() . \PHP_EOL;
23+
}
24+
?>
25+
--EXPECTF--
26+
bcround(): Argument #2 ($precision) must be between %i and %d
27+
BcMath\Number::round(): Argument #1 ($precision) must be between %i and %d
28+
BcMath\Number::round(): Argument #1 ($precision) must be between %i and %d

0 commit comments

Comments
 (0)