Skip to content

Commit 16e217e

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: ext/bcmath: bounds-check $precision in bcround() and Number::round() (php#22182)
2 parents 80d580b + c0fa54f commit 16e217e

5 files changed

Lines changed: 58 additions & 6 deletions

File tree

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.5.8
44

5+
- BCMath:
6+
. Fixed issues with oversized allocations and signed overflow in bcround()
7+
and BcMath\Number::round(). (edorian)
8+
59
- GD:
610
. Fixed bug GH-22121 (Double free in gdImageSetStyle() after
711
overflow-triggered early return). (iliaal)

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ PHP 8.5 UPGRADE NOTES
597597
5. Changed Functions
598598
========================================
599599

600+
- BCMath:
601+
. bcround() and BcMath\Number::round() now throw a ValueError when the precision
602+
argument is out of range.
603+
600604
- Intl:
601605
. IntlDateFormatter::setTimeZone()/datefmt_set_timezone()
602606
throws an IntlException on uninitialised classes/clone failures.

ext/bcmath/bcmath.c

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

160+
static zend_result bcmath_check_precision(zend_long precision, uint32_t arg_num)
161+
{
162+
if (ZEND_LONG_INT_OVFL(precision)) {
163+
zend_argument_value_error(arg_num, "must be between " ZEND_LONG_FMT " and %d",
164+
(zend_long) ZEND_LONG_MIN, INT_MAX);
165+
return FAILURE;
166+
}
167+
return SUCCESS;
168+
}
169+
160170
static void php_long2num(bc_num *num, zend_long lval)
161171
{
162172
*num = bc_long2num(lval);
@@ -798,6 +808,10 @@ PHP_FUNCTION(bcround)
798808
Z_PARAM_OBJ_OF_CLASS(mode_object, rounding_mode_ce)
799809
ZEND_PARSE_PARAMETERS_END();
800810

811+
if (bcmath_check_precision(precision, 2) == FAILURE) {
812+
RETURN_THROWS();
813+
}
814+
801815
if (mode_object != NULL) {
802816
mode = php_math_round_mode_from_enum(mode_object);
803817
}
@@ -1805,6 +1819,10 @@ PHP_METHOD(BcMath_Number, round)
18051819
Z_PARAM_OBJ_OF_CLASS(mode_object, rounding_mode_ce);
18061820
ZEND_PARSE_PARAMETERS_END();
18071821

1822+
if (bcmath_check_precision(precision, 1) == FAILURE) {
1823+
RETURN_THROWS();
1824+
}
1825+
18081826
if (mode_object != NULL) {
18091827
rounding_mode = php_math_round_mode_from_enum(mode_object);
18101828
}

ext/bcmath/libbcmath/src/round.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,10 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result)
7171
return 0;
7272
}
7373

74-
/* If precision is -3, it becomes 1000. */
75-
if (UNEXPECTED(precision == ZEND_LONG_MIN)) {
76-
*result = bc_new_num((size_t) ZEND_LONG_MAX + 2, 0);
77-
} else {
78-
*result = bc_new_num(-precision + 1, 0);
79-
}
74+
/* If precision is -3, it becomes 1000. Negate in unsigned space so
75+
* precision == ZEND_LONG_MIN doesn't overflow signed long. */
76+
zend_ulong magnitude = -(zend_ulong) precision;
77+
*result = bc_new_num((size_t) magnitude + 1, 0);
8078
(*result)->n_value[0] = 1;
8179
(*result)->n_sign = num->n_sign;
8280
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)