Skip to content

Commit 44eec94

Browse files
committed
Fixed bug #75178 (bcpowmod() misbehaves for non-integer base or modulus)
Since `bcpowmod()` does not support non-integral operands, we have to truncate these in addition to emitting a respective warning. We also have to work with the truncated values in the following. We recognize that the division by one to enforce the truncation is actually overkill, but we stick with it for now, and shall tackle the issue for PHP 7.3.
1 parent 0413feb commit 44eec94

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ PHP NEWS
88
- BCMath:
99
. Fixed bug #44995 (bcpowmod() fails if scale != 0). (cmb)
1010
. Fixed bug #54598 (bcpowmod() may return 1 if modulus is 1). (okano1220, cmb)
11+
. Fixed bug #75178 (bcpowmod() misbehaves for non-integer base or modulus). (cmb)
1112

1213
- CLI server:
1314
. Fixed bug #70470 (Built-in server truncates headers spanning over TCP

ext/bcmath/libbcmath/src/raisemod.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
int
4646
bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
4747
{
48-
bc_num power, exponent, parity, temp;
48+
bc_num power, exponent, modulus, parity, temp;
4949
int rscale;
5050

5151
/* Check for correct numbers. */
@@ -55,12 +55,16 @@ bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
5555
/* Set initial values. */
5656
power = bc_copy_num (base);
5757
exponent = bc_copy_num (expo);
58+
modulus = bc_copy_num (mod);
5859
temp = bc_copy_num (BCG(_one_));
5960
bc_init_num(&parity);
6061

6162
/* Check the base for scale digits. */
62-
if (base->n_scale != 0)
63+
if (power->n_scale != 0)
64+
{
6365
bc_rt_warn ("non-zero scale in base");
66+
bc_divide (power, BCG(_one_), &power, 0); /*truncate */
67+
}
6468

6569
/* Check the exponent for scale digits. */
6670
if (exponent->n_scale != 0)
@@ -70,12 +74,15 @@ bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
7074
}
7175

7276
/* Check the modulus for scale digits. */
73-
if (mod->n_scale != 0)
77+
if (modulus->n_scale != 0)
78+
{
7479
bc_rt_warn ("non-zero scale in modulus");
80+
bc_divide (modulus, BCG(_one_), &modulus, 0); /*truncate */
81+
}
7582

7683
/* Do the calculation. */
77-
rscale = MAX(scale, base->n_scale);
78-
if ( !bc_compare(mod, BCG(_one_)) )
84+
rscale = MAX(scale, power->n_scale);
85+
if ( !bc_compare(modulus, BCG(_one_)) )
7986
{
8087
temp = bc_new_num (1, scale);
8188
}
@@ -87,17 +94,18 @@ bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
8794
if ( !bc_is_zero(parity) )
8895
{
8996
bc_multiply (temp, power, &temp, rscale);
90-
(void) bc_modulo (temp, mod, &temp, scale);
97+
(void) bc_modulo (temp, modulus, &temp, scale);
9198
}
9299

93100
bc_multiply (power, power, &power, rscale);
94-
(void) bc_modulo (power, mod, &power, scale);
101+
(void) bc_modulo (power, modulus, &power, scale);
95102
}
96103
}
97104

98105
/* Assign the value. */
99106
bc_free_num (&power);
100107
bc_free_num (&exponent);
108+
bc_free_num (&modulus);
101109
bc_free_num (result);
102110
bc_free_num (&parity);
103111
*result = temp;

ext/bcmath/tests/bug75178.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #75178 (bcpowmod() misbehaves for non-integer base or modulus)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('bcmath')) die('skip bcmath extension is not available');
6+
?>
7+
--FILE--
8+
<?php
9+
var_dump(bcpowmod('4.1', '4', '3', 3));
10+
var_dump(bcpowmod('4', '4', '3.1', 3));
11+
?>
12+
===DONE===
13+
--EXPECT--
14+
bc math warning: non-zero scale in base
15+
string(5) "1.000"
16+
bc math warning: non-zero scale in modulus
17+
string(5) "1.000"
18+
===DONE===

0 commit comments

Comments
 (0)