From c0489931bdce6de98b322eaf5f1800c80bb143f2 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Nov 2024 16:50:16 +0900 Subject: [PATCH 1/4] 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 | 11 +++-- 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, 112 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..e8108ac61b347 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,11 @@ 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); + 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 +104,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 From 62878da32f2337c8d71d59932efec1241269253a Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 5 Nov 2024 00:42:24 +0900 Subject: [PATCH 2/4] Fixed the behavior of the bcpow() function to be the same as the Number class. --- ext/bcmath/bcmath.c | 5 ++- ext/bcmath/tests/bcpow.phpt | 54 +++++++++++++++++++------ ext/bcmath/tests/bcpow_div_by_zero.phpt | 29 +++++++++++++ ext/bcmath/tests/gh16236.phpt | 17 -------- 4 files changed, 74 insertions(+), 31 deletions(-) create mode 100644 ext/bcmath/tests/bcpow_div_by_zero.phpt delete mode 100644 ext/bcmath/tests/gh16236.phpt diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index d71e38d971ea0..1b4dd331c9b95 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -615,7 +615,10 @@ PHP_FUNCTION(bcpow) goto cleanup; } - bc_raise(first, exponent, &result, scale); + if (!bc_raise(first, exponent, &result, scale)) { + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Negative power of zero"); + goto cleanup; + } RETVAL_NEW_STR(bc_num2str_ex(result, scale)); diff --git a/ext/bcmath/tests/bcpow.phpt b/ext/bcmath/tests/bcpow.phpt index 799cbbd090bc2..b2c61fd77645f 100644 --- a/ext/bcmath/tests/bcpow.phpt +++ b/ext/bcmath/tests/bcpow.phpt @@ -6,7 +6,35 @@ bcmath bcmath.scale=0 --FILE-- getMessage(), "\n"; + } + } +} + +?> +--EXPECT-- +Negative power of zero +Negative power of zero +Negative power of zero +Negative power of zero +Negative power of zero +Negative power of zero diff --git a/ext/bcmath/tests/gh16236.phpt b/ext/bcmath/tests/gh16236.phpt deleted file mode 100644 index 3a91a63ba1053..0000000000000 --- a/ext/bcmath/tests/gh16236.phpt +++ /dev/null @@ -1,17 +0,0 @@ ---TEST-- -GH-16236 Segmentation fault (access null pointer) in ext/bcmath/libbcmath/src/rmzero.c:50 ---EXTENSIONS-- -bcmath ---FILE-- - ---EXPECT-- -done! From 4cfc7880f27699138c6f130e34029c625b56492a Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 5 Nov 2024 00:45:42 +0900 Subject: [PATCH 3/4] Fixed variable name --- ext/bcmath/libbcmath/src/bcmath.h | 2 +- ext/bcmath/libbcmath/src/raise.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index a78b61c8e70e2..9a4d1c9b4c355 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); -bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale); +bool bc_raise(bc_num base, 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 e8108ac61b347..1e283864694b6 100644 --- a/ext/bcmath/libbcmath/src/raise.c +++ b/ext/bcmath/libbcmath/src/raise.c @@ -40,10 +40,10 @@ void bc_square_ex(bc_num n1, bc_num *result, size_t scale_min) { *(result) = square_ex; } -/* Raise NUM1 to the NUM2 power. The result is placed in RESULT. - Maximum exponent is LONG_MAX. If a NUM2 is not an integer, +/* Raise "base" to the "exponent" power. The result is placed in RESULT. + Maximum exponent is LONG_MAX. If a "exponent" is not an integer, only the integer part is used. */ -bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { +bool bc_raise(bc_num base, long exponent, bc_num *result, size_t scale) { bc_num temp, power; size_t rscale; size_t pwrscale; @@ -64,12 +64,12 @@ bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) { rscale = scale; } else { is_neg = false; - rscale = MIN (num1->n_scale * exponent, MAX(scale, num1->n_scale)); + rscale = MIN (base->n_scale * exponent, MAX(scale, base->n_scale)); } /* Set initial value of temp. */ - power = bc_copy_num(num1); - pwrscale = num1->n_scale; + power = bc_copy_num(base); + pwrscale = base->n_scale; while ((exponent & 1) == 0) { pwrscale = 2 * pwrscale; bc_square_ex(power, &power, pwrscale); From 2e44b1fd70617f0d21b9bf3be34aab94da947f49 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 5 Nov 2024 08:27:40 +0900 Subject: [PATCH 4/4] Added try-catch to run_bcmath_tests_function.inc --- ext/bcmath/tests/bcpow.phpt | 54 +++++-------------- .../tests/run_bcmath_tests_function.inc | 7 ++- 2 files changed, 19 insertions(+), 42 deletions(-) diff --git a/ext/bcmath/tests/bcpow.phpt b/ext/bcmath/tests/bcpow.phpt index b2c61fd77645f..9a46152f99632 100644 --- a/ext/bcmath/tests/bcpow.phpt +++ b/ext/bcmath/tests/bcpow.phpt @@ -6,35 +6,7 @@ bcmath bcmath.scale=0 --FILE-- getMessage(); + } echo $firstTerm, " $symbol ", str_pad($secondTerm, STRING_PADDING), " = ", - $bcmath_function($firstTerm, $secondTerm, $scale), + $ret, "\n"; } echo "\n";