diff mbox

[google,annotalysis] Fix remove operation from pointer_set in case of hash collisions

Message ID CAF6KqwWcuO+kLjOKfRKK6_bWtPKSnU2JvLv1sU2N+gxtCUVFYA@mail.gmail.com
State New
Headers show

Commit Message

Delesley Hutchins July 26, 2011, 11:13 p.m. UTC
This patch fixes a bug in pointer_set.c, where removing a pointer from
a pointer set would corrupt the hash table if the pointer was involved
in any hash collisions.

Bootstrapped and passed gcc regression testsuite on x86_64-unknown-linux-gnu.

Okay for google/gcc-4_6?

  -DeLesley

gcc/Changelog.annotalysis:
2011-7-26  DeLesley Hutchins  <delesley@google.com>

        * gcc/pointer-set.c (pointer_set_delete)  bugfix for case of
hash collisions

Comments

Diego Novillo July 27, 2011, 12:59 a.m. UTC | #1
On Tue, Jul 26, 2011 at 16:13, Delesley Hutchins <delesley@google.com> wrote:
> This patch fixes a bug in pointer_set.c, where removing a pointer from
> a pointer set would corrupt the hash table if the pointer was involved
> in any hash collisions.

Could you include a test case?  It's not clear to me what you are
fixing and when this happens.  Is this a bug in trunk as well?  The
pointer-set implementation has been around for a while, so I'm
surprised that you are running into this now.  Or is this something
that only happens with the pointer set changes we have in for
annotalysis?


Thanks.  Diego.
Delesley Hutchins July 27, 2011, 2:27 a.m. UTC | #2
Le-Chun added the additional routine to remove pointers from a set;
that code is unique to annotalysis.  I can't easily include a test
case, because the bug is difficult to trigger.  It occurs only when
there is a hash collision between two pointers in the set, and the
first pointer is removed before the second.  I do have a test case,
but it will only work for my particular build on my machine, since the
actual pointer addresses involved will change as soon as you touch
something.  I could write a unit test using bogus pointer values that
are engineered to trigger a collision, but it wouldn't be a normal
compiler test case; where would I put it?

  -DeLesley

On Tue, Jul 26, 2011 at 5:59 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Tue, Jul 26, 2011 at 16:13, Delesley Hutchins <delesley@google.com> wrote:
>> This patch fixes a bug in pointer_set.c, where removing a pointer from
>> a pointer set would corrupt the hash table if the pointer was involved
>> in any hash collisions.
>
> Could you include a test case?  It's not clear to me what you are
> fixing and when this happens.  Is this a bug in trunk as well?  The
> pointer-set implementation has been around for a while, so I'm
> surprised that you are running into this now.  Or is this something
> that only happens with the pointer set changes we have in for
> annotalysis?
>
>
> Thanks.  Diego.
>
Richard Henderson July 28, 2011, 7:22 p.m. UTC | #3
On 07/26/2011 04:13 PM, Delesley Hutchins wrote:
> This patch fixes a bug in pointer_set.c, where removing a pointer from
> a pointer set would corrupt the hash table if the pointer was involved
> in any hash collisions.
> 
> Bootstrapped and passed gcc regression testsuite on x86_64-unknown-linux-gnu.
> 
> Okay for google/gcc-4_6?
> 
>   -DeLesley
> 
> gcc/Changelog.annotalysis:
> 2011-7-26  DeLesley Hutchins  <delesley@google.com>
> 
>         * gcc/pointer-set.c (pointer_set_delete)  bugfix for case of
> hash collisions

The logic of the patch looks good.  I certainly agree it's a real bug.

> +  /* find location of p */

But please fix up all the comments to be properly punctuated sentences.

> +      pset->slots[n] = 0;      /* remove ptr from set. */

And avoid end-of-line comments.  Put it on the previous line.


r~
Ollie Wild July 29, 2011, 5:10 p.m. UTC | #4
Okay for google/gcc-4_6.

Ollie

On Tue, Jul 26, 2011 at 7:27 PM, Delesley Hutchins <delesley@google.com> wrote:
>
> Le-Chun added the additional routine to remove pointers from a set;
> that code is unique to annotalysis.  I can't easily include a test
> case, because the bug is difficult to trigger.  It occurs only when
> there is a hash collision between two pointers in the set, and the
> first pointer is removed before the second.  I do have a test case,
> but it will only work for my particular build on my machine, since the
> actual pointer addresses involved will change as soon as you touch
> something.  I could write a unit test using bogus pointer values that
> are engineered to trigger a collision, but it wouldn't be a normal
> compiler test case; where would I put it?
>
>  -DeLesley
>
> On Tue, Jul 26, 2011 at 5:59 PM, Diego Novillo <dnovillo@google.com> wrote:
> > On Tue, Jul 26, 2011 at 16:13, Delesley Hutchins <delesley@google.com> wrote:
> >> This patch fixes a bug in pointer_set.c, where removing a pointer from
> >> a pointer set would corrupt the hash table if the pointer was involved
> >> in any hash collisions.
> >
> > Could you include a test case?  It's not clear to me what you are
> > fixing and when this happens.  Is this a bug in trunk as well?  The
> > pointer-set implementation has been around for a while, so I'm
> > surprised that you are running into this now.  Or is this something
> > that only happens with the pointer set changes we have in for
> > annotalysis?
> >
> >
> > Thanks.  Diego.
> >
>
>
>
> --
> DeLesley Hutchins | Software Engineer | delesley@google.com | 505-206-0315
diff mbox

Patch

Index: gcc/pointer-set.c
===================================================================
--- gcc/pointer-set.c	(revision 176809)
+++ gcc/pointer-set.c	(working copy)
@@ -192,19 +192,16 @@  int
 pointer_set_delete (struct pointer_set_t *pset, const void *p)
 {
   size_t n = hash1 (p, pset->n_slots, pset->log_slots);
+  size_t n2;
+  const void* ptr;

+  /* find location of p */
   while (true)
     {
       if (pset->slots[n] == p)
-        {
-          pset->slots[n] = 0;
-          --pset->n_elements;
-          return 1;
-        }
+        break;
       else if (pset->slots[n] == 0)
-        {
-          return 0;
-        }
+        return 0;
       else
         {
           ++n;
@@ -212,6 +209,29 @@  pointer_set_delete (struct pointer_set_t *pset, co
             n = 0;
         }
     }
+
+  /* Remove p from set. */
+  pset->slots[n] = 0;
+
+  /* Now we need to scan foward and re-hash every value that we encounter,
+     until we find an empty slot.
+   */
+  while (true)
+    {
+      ++n;
+      if (n >= pset->n_slots)
+        n = 0;
+      ptr = pset->slots[n];
+
+      if (ptr == 0) break;
+
+      pset->slots[n] = 0;      /* remove ptr from set. */
+      n2 = insert_aux(ptr, pset->slots, pset->n_slots, pset->log_slots);
+      pset->slots[n2] = ptr;   /* put ptr back in set. */
+    }
+
+  --pset->n_elements;
+  return 1;
 }

 /* Pass each pointer in PSET to the function in FN, together with the fixed