mpi: Fix a subtle bug setting spurious bits with in mpi_set_bit.
authorWerner Koch <wk@gnupg.org>
Fri, 9 May 2014 10:35:15 +0000 (12:35 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 9 May 2014 10:36:54 +0000 (12:36 +0200)
* mpi/mpi-bit.c (_gcry_mpi_set_bit, _gcry_mpi_set_highbit): Clear
allocated but not used bits before resizing.
* tests/t-mpi-bits.c (set_bit_with_resize): New.
--

Reported-by: Martin Sewelies.
This bug is probably with us for many years.  Probably due to
different memory allocation patterns, it did first revealed itself
with 1.6.  It could be the reason for other heisenbugs.

Signed-off-by: Werner Koch <wk@gnupg.org>
mpi/mpi-bit.c
tests/t-mpi-bit.c

index fcafda0..e217040 100644 (file)
@@ -116,7 +116,7 @@ _gcry_mpi_test_bit( gcry_mpi_t a, unsigned int n )
 void
 _gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
 {
-  unsigned int limbno, bitno;
+  unsigned int i, limbno, bitno;
 
   if (mpi_is_immutable (a))
     {
@@ -129,6 +129,8 @@ _gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
 
   if ( limbno >= a->nlimbs )
     {
+      for (i=a->nlimbs; i < a->alloced; i++)
+        a->d[i] = 0;
       mpi_resize (a, limbno+1 );
       a->nlimbs = limbno+1;
     }
@@ -141,7 +143,7 @@ _gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
 void
 _gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
 {
-  unsigned int limbno, bitno;
+  unsigned int i, limbno, bitno;
 
   if (mpi_is_immutable (a))
     {
@@ -154,6 +156,8 @@ _gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
 
   if ( limbno >= a->nlimbs )
     {
+      for (i=a->nlimbs; i < a->alloced; i++)
+        a->d[i] = 0;
       mpi_resize (a, limbno+1 );
       a->nlimbs = limbno+1;
     }
index b1c999e..3d7b793 100644 (file)
@@ -327,6 +327,58 @@ test_lshift (int pass)
 }
 
 
+/* Bug fixed on 2014-05-09:
+      a = gcry_mpi_new (1523);
+      gcry_mpi_set_bit (a, 1536);
+      didn't initialized all limbs in A.  */
+static void
+set_bit_with_resize (void)
+{
+  gcry_mpi_t a;
+  int i;
+
+  wherestr = "set_bit_with_resize";
+  show ("checking that set_bit initializes all limbs\n");
+
+  a = gcry_mpi_new (1536);
+  gcry_mpi_set_bit (a, 1536);
+
+  if (!gcry_mpi_test_bit (a, 1536))
+    fail ("failed to set a bit\n");
+  for (i=0; i < 1536; i++)
+    {
+      if (gcry_mpi_test_bit (a, i))
+        {
+          fail ("spurious bit detected\n");
+          break;
+        }
+    }
+  if (gcry_mpi_test_bit (a, 1537))
+    fail ("more bits set than expected\n");
+  gcry_mpi_release (a);
+
+  wherestr = "set_highbit_with_resize";
+  show ("checking that set_highbit initializes all limbs\n");
+
+  a = gcry_mpi_new (1536);
+  gcry_mpi_set_highbit (a, 1536);
+
+  if (!gcry_mpi_test_bit (a, 1536))
+    fail ("failed to set a bit\n");
+  for (i=0; i < 1536; i++)
+    {
+      if (gcry_mpi_test_bit (a, i))
+        {
+          fail ("spurious bit detected\n");
+          break;
+        }
+    }
+  if (gcry_mpi_test_bit (a, 1537))
+    fail ("more bits set than expected\n");
+  gcry_mpi_release (a);
+}
+
+
 int
 main (int argc, char **argv)
 {
@@ -356,6 +408,8 @@ main (int argc, char **argv)
   for (i=0; i < 5; i++)
     test_lshift (i); /* Run several times due to random initializations. */
 
+  set_bit_with_resize ();
+
   show ("All tests completed. Errors: %d\n", error_count);
   return error_count ? 1 : 0;
 }