Skip to content

Commit c048993

Browse files
committed
Fixed a bug in BcMath\Number::pow() when raising negative powers of 0.
1 parent 5c7c5d9 commit c048993

File tree

6 files changed

+112
-5
lines changed

6 files changed

+112
-5
lines changed

ext/bcmath/bcmath.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,10 @@ static zend_result bcmath_number_pow_internal(
11411141
}
11421142
return FAILURE;
11431143
}
1144-
bc_raise(n1, exponent, ret, *scale);
1144+
if (!bc_raise(n1, exponent, ret, *scale)) {
1145+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Negative power of zero");
1146+
return FAILURE;
1147+
}
11451148
bc_rm_trailing_zeros(*ret);
11461149
if (scale_expand) {
11471150
size_t diff = *scale - (*ret)->n_scale;

ext/bcmath/libbcmath/src/bcmath.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ typedef enum {
173173

174174
raise_mod_status bc_raisemod(bc_num base, bc_num exponent, bc_num mod, bc_num *result, size_t scale);
175175

176-
void bc_raise(bc_num base, long exponent, bc_num *resul, size_t scale);
176+
bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale);
177177

178178
void bc_raise_bc_exponent(bc_num base, bc_num exponent, bc_num *resul, size_t scale);
179179

ext/bcmath/libbcmath/src/raise.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void bc_square_ex(bc_num n1, bc_num *result, size_t scale_min) {
4343
/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
4444
Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
4545
only the integer part is used. */
46-
void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) {
46+
bool bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) {
4747
bc_num temp, power;
4848
size_t rscale;
4949
size_t pwrscale;
@@ -54,7 +54,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) {
5454
if (exponent == 0) {
5555
bc_free_num (result);
5656
*result = bc_copy_num(BCG(_one_));
57-
return;
57+
return true;
5858
}
5959

6060
/* Other initializations. */
@@ -92,14 +92,19 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) {
9292

9393
/* Assign the value. */
9494
if (is_neg) {
95-
bc_divide(BCG(_one_), temp, result, rscale);
95+
if (bc_divide(BCG(_one_), temp, result, rscale) == false) {
96+
bc_free_num (&temp);
97+
bc_free_num (&power);
98+
return false;
99+
}
96100
bc_free_num (&temp);
97101
} else {
98102
bc_free_num (result);
99103
*result = temp;
100104
(*result)->n_scale = MIN(scale, (*result)->n_scale);
101105
}
102106
bc_free_num (&power);
107+
return true;
103108
}
104109

105110
/* This is used internally by BCMath */

ext/bcmath/tests/gh16236.phpt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
GH-16236 Segmentation fault (access null pointer) in ext/bcmath/libbcmath/src/rmzero.c:50
3+
--EXTENSIONS--
4+
bcmath
5+
--FILE--
6+
<?php
7+
/**
8+
* The existing bcpow() specification returns 0 for negative powers.
9+
* This is mathematically incorrect and will need to be changed to raise an error at some point.
10+
* This test is to ensure the existing specifications until the specifications are changed.
11+
*/
12+
bcpow('0', '-2');
13+
14+
echo 'done!';
15+
?>
16+
--EXPECT--
17+
done!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
BcMath\Number pow(): negative power of zero
3+
--EXTENSIONS--
4+
bcmath
5+
--FILE--
6+
<?php
7+
8+
$values = [0, '0'];
9+
10+
$exponents = [
11+
[-3, 'int'],
12+
['-2', 'string'],
13+
[new BcMath\Number('-2'), 'object'],
14+
];
15+
16+
foreach ($values as $value) {
17+
$num = new BcMath\Number($value);
18+
19+
foreach ($exponents as [$exponent, $type]) {
20+
echo "{$value} ** {$exponent}: {$type}\n";
21+
try {
22+
$num->pow($exponent);
23+
} catch (Error $e) {
24+
echo $e->getMessage() . "\n";
25+
}
26+
}
27+
}
28+
?>
29+
--EXPECT--
30+
0 ** -3: int
31+
Negative power of zero
32+
0 ** -2: string
33+
Negative power of zero
34+
0 ** -2: object
35+
Negative power of zero
36+
0 ** -3: int
37+
Negative power of zero
38+
0 ** -2: string
39+
Negative power of zero
40+
0 ** -2: object
41+
Negative power of zero
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
BcMath\Number pow: negative power of zero by operator
3+
--EXTENSIONS--
4+
bcmath
5+
--FILE--
6+
<?php
7+
8+
$values = [0, '0'];
9+
10+
$exponents = [
11+
[-3, 'int'],
12+
['-2', 'string'],
13+
[new BcMath\Number('-2'), 'object'],
14+
];
15+
16+
foreach ($values as $value) {
17+
$num = new BcMath\Number($value);
18+
19+
foreach ($exponents as [$exponent, $type]) {
20+
echo "{$value} ** {$exponent}: {$type}\n";
21+
try {
22+
$num ** $exponent;
23+
} catch (Error $e) {
24+
echo $e->getMessage() . "\n";
25+
}
26+
}
27+
}
28+
?>
29+
--EXPECT--
30+
0 ** -3: int
31+
Negative power of zero
32+
0 ** -2: string
33+
Negative power of zero
34+
0 ** -2: object
35+
Negative power of zero
36+
0 ** -3: int
37+
Negative power of zero
38+
0 ** -2: string
39+
Negative power of zero
40+
0 ** -2: object
41+
Negative power of zero

0 commit comments

Comments
 (0)