]> granicus.if.org Git - php/commitdiff
Fixed bug #75178 (bcpowmod() misbehaves for non-integer base or modulus)
authorChristoph M. Becker <cmbecker69@gmx.de>
Sat, 9 Sep 2017 11:18:26 +0000 (13:18 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Sat, 9 Sep 2017 11:18:26 +0000 (13:18 +0200)
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.

NEWS
ext/bcmath/libbcmath/src/raisemod.c
ext/bcmath/tests/bug75178.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 7fb0cb106576b909364aa46621ad51eeb17aab42..795d67d860e5321be1acabfc37b04d2aab2f7585 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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
index 84a7321ea7a6b769885b902924de3ca2ffef19c8..84788b4770cf52814cc44d1cbbc324ddad661ea0 100644 (file)
@@ -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. */
@@ -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)
@@ -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);
     }
@@ -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;
diff --git a/ext/bcmath/tests/bug75178.phpt b/ext/bcmath/tests/bug75178.phpt
new file mode 100644 (file)
index 0000000..4e25256
--- /dev/null
@@ -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===