From 8a04775a2502153befb981ecf6c3161f636b9ecc Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Nov 2024 16:45:09 +0900 Subject: [PATCH] Fixed a bug in BcMath\Number::pow() when raising negative powers of 0. --- ext/bcmath/bcmath.c | 5 ++- ext/bcmath/libbcmath/src/bcmath.h | 2 +- ext/bcmath/libbcmath/src/raise.c | 12 ++++-- ext/bcmath/tests/gh16236.phpt | 17 ++++++++ .../tests/number/methods/pow_div_by_zero.phpt | 41 +++++++++++++++++++ .../number/operators/pow_div_by_zero.phpt | 41 +++++++++++++++++++ 6 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 ext/bcmath/tests/gh16236.phpt create mode 100644 ext/bcmath/tests/number/methods/pow_div_by_zero.phpt create mode 100644 ext/bcmath/tests/number/operators/pow_div_by_zero.phpt diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index c7c5aeb700fbe..d71e38d971ea0 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -1141,7 +1141,10 @@ static zend_result bcmath_number_pow_internal( } return FAILURE; } - bc_raise(n1, exponent, ret, *scale); + if (!bc_raise(n1, exponent, ret, *scale)) { + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Negative power of zero"); + return FAILURE; + } bc_rm_trailing_zeros(*ret); if (scale_expand) { size_t diff = *scale - (*ret)->n_scale; diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index 4b8ca12326417..a78b61c8e70e2 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -173,7 +173,7 @@ typedef enum { raise_mod_status bc_raisemod(bc_num base, bc_num exponent, bc_num mod, bc_num *result, size_t scale); -void bc_raise(bc_num base, long exponent, bc_num *resul, size_t scale); +bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale); void bc_raise_bc_exponent(bc_num base, bc_num exponent, bc_num *resul, size_t scale); diff --git a/ext/bcmath/libbcmath/src/raise.c b/ext/bcmath/libbcmath/src/raise.c index 162f84a830538..a12f9b41d47ec 100644 --- a/ext/bcmath/libbcmath/src/raise.c +++ b/ext/bcmath/libbcmath/src/raise.c @@ -43,7 +43,7 @@ void bc_square_ex(bc_num n1, bc_num *result, size_t scale_min) { /* Raise NUM1 to the NUM2 power. The result is placed in RESULT. Maximum exponent is LONG_MAX. If a NUM2 is not an integer, only the integer part is used. */ -void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { +bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { bc_num temp, power; size_t rscale; size_t pwrscale; @@ -54,7 +54,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { if (exponent == 0) { bc_free_num (result); *result = bc_copy_num(BCG(_one_)); - return; + return true; } /* Other initializations. */ @@ -92,7 +92,12 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { /* Assign the value. */ if (is_neg) { - bc_divide(BCG(_one_), temp, result, rscale); + // TODO: After removing bcpow's bc_init_num(), remove the NULL check + if (bc_divide(BCG(_one_), temp, result, rscale) == false) { + bc_free_num (&temp); + bc_free_num (&power); + return false; + } bc_free_num (&temp); } else { bc_free_num (result); @@ -100,6 +105,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { (*result)->n_scale = MIN(scale, (*result)->n_scale); } bc_free_num (&power); + return true; } /* This is used internally by BCMath */ diff --git a/ext/bcmath/tests/gh16236.phpt b/ext/bcmath/tests/gh16236.phpt new file mode 100644 index 0000000000000..3a91a63ba1053 --- /dev/null +++ b/ext/bcmath/tests/gh16236.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-16236 Segmentation fault (access null pointer) in ext/bcmath/libbcmath/src/rmzero.c:50 +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/pow_div_by_zero.phpt b/ext/bcmath/tests/number/methods/pow_div_by_zero.phpt new file mode 100644 index 0000000000000..6a7099b1c30ee --- /dev/null +++ b/ext/bcmath/tests/number/methods/pow_div_by_zero.phpt @@ -0,0 +1,41 @@ +--TEST-- +BcMath\Number pow(): negative power of zero +--EXTENSIONS-- +bcmath +--FILE-- +pow($exponent); + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } + } +} +?> +--EXPECT-- +0 ** -3: int +Negative power of zero +0 ** -2: string +Negative power of zero +0 ** -2: object +Negative power of zero +0 ** -3: int +Negative power of zero +0 ** -2: string +Negative power of zero +0 ** -2: object +Negative power of zero diff --git a/ext/bcmath/tests/number/operators/pow_div_by_zero.phpt b/ext/bcmath/tests/number/operators/pow_div_by_zero.phpt new file mode 100644 index 0000000000000..ff03626fca600 --- /dev/null +++ b/ext/bcmath/tests/number/operators/pow_div_by_zero.phpt @@ -0,0 +1,41 @@ +--TEST-- +BcMath\Number pow: negative power of zero by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; + } + } +} +?> +--EXPECT-- +0 ** -3: int +Negative power of zero +0 ** -2: string +Negative power of zero +0 ** -2: object +Negative power of zero +0 ** -3: int +Negative power of zero +0 ** -2: string +Negative power of zero +0 ** -2: object +Negative power of zero