bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Akim Demaille <akim@lrde.epita.fr>
To: Bruno Haible <bruno@clisp.org>
Cc: bug-gnulib@gnu.org
Subject: Re: undefined behaviour findings in bitset
Date: Sat, 16 Mar 2019 17:38:03 +0100	[thread overview]
Message-ID: <A0703AEA-16AA-45FC-A393-77A2583A6592@lrde.epita.fr> (raw)
In-Reply-To: <62113576.DJnoC0p1FV@omega>

Hi Bruno,

> Le 9 mars 2019 à 20:37, Bruno Haible <bruno@clisp.org> a écrit :
> 
> Hi Akim,
> 
> This one I have not fixed:
> 
> lib/bitset/table.c:784:54: runtime error: shift exponent 87 is too large for 64-bit type 'long unsigned int'
> 
> To reproduce: Use gcc 8.2.0 and CC="gcc -fsanitize=undefined".

Thanks for the report!  Here is my proposal, in three patches.

commit 6f8b57537eb47418a432b672cbb240713f005a6a
Author: Akim Demaille <akim.demaille@gmail.com>
Date:   Thu Mar 14 08:31:54 2019 +0100

    bitset: style changes
    
    * lib/bitset/table.c: Use NULL, not 0, for pointers.
    Formatting changes.
    (tbitset_list): Reduce scopes.

diff --git a/ChangeLog b/ChangeLog
index 544d69d4b..2352520a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2019-03-14  Akim Demaille  <akim@lrde.epita.fr>
+
+	bitset: style changes.
+	* lib/bitset/table.c: Use NULL, not 0, for pointers.
+	Formatting changes.
+	(tbitset_list): Reduce scopes.
+
 2019-03-14  Bruno Haible  <bruno@clisp.org>
 
 	isatty: Make it return true in Cygwin consoles on native Windows.
diff --git a/lib/bitset/table.c b/lib/bitset/table.c
index 8351cf784..a129c8712 100644
--- a/lib/bitset/table.c
+++ b/lib/bitset/table.c
@@ -300,7 +300,7 @@ tbitset_elt_find (bitset bset, bitset_bindex bindex,
       abort ();
 
     case EBITSET_FIND:
-      return 0;
+      return NULL;
 
     case EBITSET_CREATE:
       if (eindex >= size)
@@ -588,8 +588,8 @@ tbitset_list_reverse (bitset bset, bitset_bindex *list,
 
 
 /* Find list of up to NUM bits set in BSET starting from and including
- *NEXT and store in array LIST.  Return with actual number of bits
- found and with *NEXT indicating where search stopped.  */
+   *NEXT and store in array LIST.  Return with actual number of bits
+   found and with *NEXT indicating where search stopped.  */
 static bitset_bindex
 tbitset_list (bitset bset, bitset_bindex *list,
               bitset_bindex num, bitset_bindex *next)
@@ -607,17 +607,14 @@ tbitset_list (bitset bset, bitset_bindex *list,
   if (bitno % EBITSET_ELT_BITS)
     {
       /* We need to start within an element.  This is not very common.  */
-
       tbitset_elt *elt = elts[eindex];
       if (elt)
         {
-          bitset_windex woffset;
           bitset_word *srcp = EBITSET_WORDS (elt);
+          bitset_windex woffset = eindex * EBITSET_ELT_WORDS;
 
-          bitset_windex windex = bitno / BITSET_WORD_BITS;
-          woffset = eindex * EBITSET_ELT_WORDS;
-
-          for (; (windex - woffset) < EBITSET_ELT_WORDS; windex++)
+          for (bitset_windex windex = bitno / BITSET_WORD_BITS;
+               (windex - woffset) < EBITSET_ELT_WORDS; windex++)
             {
               bitset_word word = srcp[windex - woffset] >> (bitno % BITSET_WORD_BITS);
 



commit f4a85b4ffa59650c36227fc94e4c5973e6449d48
Author: Akim Demaille <akim.demaille@gmail.com>
Date:   Sat Mar 16 17:16:48 2019 +0100

    bitset: fix bitset overflows
    
    Reported by Bruno Haible.
    https://lists.gnu.org/archive/html/bug-gnulib/2019-03/msg00017.html
    
    * lib/bitset/table.c (tbitset_test): last_bit is the position of
    the bit in the array of bitset_word, so be sure to take its modulo
    number-of-bits-in-bitset-word (i.e., EBITSET_ELT_WORDS).
    * lib/bitset/list.c (lbitset_unused_clear): Likewise.

diff --git a/ChangeLog b/ChangeLog
index 2352520a5..0e7a74a10 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2019-03-16  Akim Demaille  <akim@lrde.epita.fr>
+
+	bitset: fix bitset overflows.
+	Reported by Bruno Haible.
+	https://lists.gnu.org/archive/html/bug-gnulib/2019-03/msg00017.html
+	* lib/bitset/table.c (tbitset_test): last_bit is the position of
+	the bit in the array of bitset_word, so be sure to take its modulo
+	number-of-bits-in-bitset-word (i.e., EBITSET_ELT_WORDS).
+	* lib/bitset/list.c (lbitset_unused_clear): Likewise.
+
 2019-03-14  Akim Demaille  <akim@lrde.epita.fr>
 
 	bitset: style changes.
diff --git a/lib/bitset/list.c b/lib/bitset/list.c
index f42edb8ea..fe1b52869 100644
--- a/lib/bitset/list.c
+++ b/lib/bitset/list.c
@@ -859,7 +859,8 @@ lbitset_unused_clear (bitset dst)
       bitset_word *srcp = elt->words;
       bitset_windex windex = n_bits / BITSET_WORD_BITS;
 
-      srcp[windex - elt->index] &= ((bitset_word) 1 << last_bit) - 1;
+      srcp[windex - elt->index]
+        &= ((bitset_word) 1 << (last_bit % BITSET_WORD_BITS)) - 1;
       windex++;
 
       for (; (windex - elt->index) < LBITSET_ELT_WORDS; windex++)
diff --git a/lib/bitset/table.c b/lib/bitset/table.c
index a129c8712..9cac96469 100644
--- a/lib/bitset/table.c
+++ b/lib/bitset/table.c
@@ -778,7 +778,8 @@ tbitset_unused_clear (bitset dst)
           bitset_windex windex = n_bits / BITSET_WORD_BITS;
           bitset_windex woffset = eindex * EBITSET_ELT_WORDS;
 
-          srcp[windex - woffset] &= ((bitset_word) 1 << last_bit) - 1;
+          srcp[windex - woffset]
+            &= ((bitset_word) 1 << (last_bit % BITSET_WORD_BITS)) - 1;
           windex++;
           for (; (windex - woffset) < EBITSET_ELT_WORDS; windex++)
             srcp[windex - woffset] = 0;



commit 4c8a35ed125e1b87a11d6aecd0b7b216384552bb
Author: Akim Demaille <akim.demaille@gmail.com>
Date:   Sat Mar 16 17:36:22 2019 +0100

    bitset: a bit (...) more tests
    
    * tests/test-bitset.c (check_attributes): Check zero and ones.

diff --git a/ChangeLog b/ChangeLog
index 0e7a74a10..db23ee898 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2019-03-16  Akim Demaille  <akim@lrde.epita.fr>
+
+	bitset: a bit (...) more tests
+	* tests/test-bitset.c (check_attributes): Check zero and ones.
+
 2019-03-16  Akim Demaille  <akim@lrde.epita.fr>
 
 	bitset: fix bitset overflows.
diff --git a/tests/test-bitset.c b/tests/test-bitset.c
index 032865095..f4502d1d6 100644
--- a/tests/test-bitset.c
+++ b/tests/test-bitset.c
@@ -32,12 +32,18 @@ void assert_bitset_equal (bitset bs1, bitset bs2)
     ASSERT (bitset_test (bs1, i) == bitset_test (bs2, i));
 }
 
+static
 void bitset_random (bitset bs)
 {
   for (bitset_bindex i = 0; i < bitset_size (bs); ++i)
     bitset_set (bs, RANDOM (2));
 }
 
+
+/* Check various operations on random bitsets with two different
+   implementations.  */
+
+static
 void compare (enum bitset_attr a, enum bitset_attr b)
 {
   const int nbits = RANDOM (256);
@@ -62,10 +68,17 @@ void compare (enum bitset_attr a, enum bitset_attr b)
   bitset_copy (bsrc3, asrc3);
   bitset bdst = bitset_create (nbits, b);
 
+  /* not */
+  bitset_not (adst, asrc0);
+  bitset_not (bdst, bsrc0);
+  assert_bitset_equal (adst, bdst);
+
+  /* not */
   bitset_not (adst, asrc0);
   bitset_not (bdst, bsrc0);
   assert_bitset_equal (adst, bdst);
 
+  /* and */
   bitset_and (adst, asrc0, asrc1);
   bitset_and (bdst, bsrc0, bsrc1);
   assert_bitset_equal (adst, bdst);
@@ -73,6 +86,7 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_and_cmp (bdst, bsrc0, bsrc1));
   assert_bitset_equal (adst, bdst);
 
+  /* andn */
   bitset_andn (adst, asrc0, asrc1);
   bitset_andn (bdst, bsrc0, bsrc1);
   assert_bitset_equal (adst, bdst);
@@ -80,6 +94,7 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_andn_cmp (bdst, bsrc0, bsrc1));
   assert_bitset_equal (adst, bdst);
 
+  /* or */
   bitset_or (adst, asrc0, asrc1);
   bitset_or (bdst, bsrc0, bsrc1);
   assert_bitset_equal (adst, bdst);
@@ -87,6 +102,7 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_or_cmp (bdst, bsrc0, bsrc1));
   assert_bitset_equal (adst, bdst);
 
+  /* xor */
   bitset_xor (adst, asrc0, asrc1);
   bitset_xor (bdst, bsrc0, bsrc1);
   assert_bitset_equal (adst, bdst);
@@ -94,6 +110,7 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_xor_cmp (bdst, bsrc0, bsrc1));
   assert_bitset_equal (adst, bdst);
 
+  /* and_or */
   bitset_and_or (adst, asrc0, asrc1, asrc2);
   bitset_and_or (bdst, bsrc0, bsrc1, bsrc2);
   assert_bitset_equal (adst, bdst);
@@ -101,6 +118,7 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_and_or_cmp (bdst, bsrc0, bsrc1, bsrc2));
   assert_bitset_equal (adst, bdst);
 
+  /* andn_or */
   bitset_andn_or (adst, asrc0, asrc1, asrc2);
   bitset_andn_or (bdst, bsrc0, bsrc1, bsrc2);
   assert_bitset_equal (adst, bdst);
@@ -108,6 +126,7 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_andn_or_cmp (bdst, bsrc0, bsrc1, bsrc2));
   assert_bitset_equal (adst, bdst);
 
+  /* or_and */
   bitset_or_and (adst, asrc0, asrc1, asrc2);
   bitset_or_and (bdst, bsrc0, bsrc1, bsrc2);
   assert_bitset_equal (adst, bdst);
@@ -115,6 +134,16 @@ void compare (enum bitset_attr a, enum bitset_attr b)
           == bitset_or_and_cmp (bdst, bsrc0, bsrc1, bsrc2));
   assert_bitset_equal (adst, bdst);
 
+  /* ones */
+  bitset_ones (adst);
+  bitset_ones (bdst);
+  assert_bitset_equal (adst, bdst);
+
+  /* zero */
+  bitset_zero (adst);
+  bitset_zero (bdst);
+  assert_bitset_equal (adst, bdst);
+  
   bitset_free (bdst);
   bitset_free (bsrc3);
   bitset_free (bsrc2);
@@ -127,6 +156,11 @@ void compare (enum bitset_attr a, enum bitset_attr b)
   bitset_free (asrc0);
 }
 
+
+/* Check various operations against expected values for a bitset
+   having attributes ATTR.  */
+
+static
 void check_attributes (enum bitset_attr attr)
 {
   enum { nbits = 32 };



  reply	other threads:[~2019-03-16 16:38 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-09 19:33 undefined behaviour findings Bruno Haible
2019-03-09 19:37 ` undefined behaviour findings in bitset Bruno Haible
2019-03-16 16:38   ` Akim Demaille [this message]
2019-03-16 16:42     ` Akim Demaille
2019-03-16 19:53     ` Bruno Haible
2019-03-17  7:39       ` Akim Demaille
2019-03-17 18:36         ` Akim Demaille
2019-03-17 18:56           ` Paul Eggert
2019-03-17 19:27           ` Bruno Haible
2019-03-18  8:16             ` Akim Demaille
2019-03-18 21:03               ` Bruno Haible
2019-03-19  6:07                 ` Akim Demaille
2019-03-22 16:00                   ` Akim Demaille
2019-03-23 18:54                     ` Bruno Haible
2019-03-20  3:39               ` Bruno Haible
2019-03-20 17:04                 ` Akim Demaille
2019-03-09 21:22 ` undefined behaviour findings Bruno Haible

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=A0703AEA-16AA-45FC-A393-77A2583A6592@lrde.epita.fr \
    --to=akim@lrde.epita.fr \
    --cc=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).