Skip to content

Commit

Permalink
Fixed bug #75178 (bcpowmod() misbehaves for non-integer base or modulus)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cmb69 committed Sep 9, 2017
1 parent 0413feb commit 44eec94
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 7 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ PHP NEWS
- BCMath:
. Fixed bug #44995 (bcpowmod() fails if scale != 0). (cmb)
. Fixed bug #54598 (bcpowmod() may return 1 if modulus is 1). (okano1220, cmb)
. Fixed bug #75178 (bcpowmod() misbehaves for non-integer base or modulus). (cmb)

- CLI server:
. Fixed bug #70470 (Built-in server truncates headers spanning over TCP
Expand Down
22 changes: 15 additions & 7 deletions ext/bcmath/libbcmath/src/raisemod.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
int
bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
{
bc_num power, exponent, parity, temp;
bc_num power, exponent, modulus, parity, temp;
int rscale;

/* Check for correct numbers. */
Expand All @@ -55,12 +55,16 @@ bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
/* Set initial values. */
power = bc_copy_num (base);
exponent = bc_copy_num (expo);
modulus = bc_copy_num (mod);
temp = bc_copy_num (BCG(_one_));
bc_init_num(&parity);

/* Check the base for scale digits. */
if (base->n_scale != 0)
if (power->n_scale != 0)
{
bc_rt_warn ("non-zero scale in base");
bc_divide (power, BCG(_one_), &power, 0); /*truncate */
}

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

/* Check the modulus for scale digits. */
if (mod->n_scale != 0)
if (modulus->n_scale != 0)
{
bc_rt_warn ("non-zero scale in modulus");
bc_divide (modulus, BCG(_one_), &modulus, 0); /*truncate */
}

/* Do the calculation. */
rscale = MAX(scale, base->n_scale);
if ( !bc_compare(mod, BCG(_one_)) )
rscale = MAX(scale, power->n_scale);
if ( !bc_compare(modulus, BCG(_one_)) )
{
temp = bc_new_num (1, scale);
}
Expand All @@ -87,17 +94,18 @@ bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
if ( !bc_is_zero(parity) )
{
bc_multiply (temp, power, &temp, rscale);
(void) bc_modulo (temp, mod, &temp, scale);
(void) bc_modulo (temp, modulus, &temp, scale);
}

bc_multiply (power, power, &power, rscale);
(void) bc_modulo (power, mod, &power, scale);
(void) bc_modulo (power, modulus, &power, scale);
}
}

/* Assign the value. */
bc_free_num (&power);
bc_free_num (&exponent);
bc_free_num (&modulus);
bc_free_num (result);
bc_free_num (&parity);
*result = temp;
Expand Down
18 changes: 18 additions & 0 deletions ext/bcmath/tests/bug75178.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Bug #75178 (bcpowmod() misbehaves for non-integer base or modulus)
--SKIPIF--
<?php
if (!extension_loaded('bcmath')) die('skip bcmath extension is not available');
?>
--FILE--
<?php
var_dump(bcpowmod('4.1', '4', '3', 3));
var_dump(bcpowmod('4', '4', '3.1', 3));
?>
===DONE===
--EXPECT--
bc math warning: non-zero scale in base
string(5) "1.000"
bc math warning: non-zero scale in modulus
string(5) "1.000"
===DONE===

0 comments on commit 44eec94

Please sign in to comment.