On Sat, 8 Dec 2007, Julian Seward wrote:

they treat
the words as signed, do a subtraction, the result is treated as signed,
and the result is checked for < 0 or > 0.

If the subtraction overflows then it is incorrect to compare the "result"
(while forgetting about the Carry) to 0.

Hmm, yes.  Wasn't there a giant storm in a teacup on the gcc list a while
back about whether gcc should optimise on the basis that overflow of signed
arithmetic is undefined?

I don't understand why the carry bit is important...

But here's a patch that should fix the problem. It uses a slower but safer and easier-to-understand method to compute the result.

Tom, can you apply and see if it fixes the problem? If so, I guess it should be committed for 3.3.0.

Nick
Index: include/pub_tool_oset.h
===================================================================
--- include/pub_tool_oset.h     (revision 7273)
+++ include/pub_tool_oset.h     (working copy)
@@ -72,7 +72,7 @@
 
 typedef struct _OSet     OSet;
 
-// - Cmp: returns -1, 0 or 1 if key is <=, == or >= elem.
+// - Cmp: returns -1, 0 or 1 if key is <, == or > elem.
 // - Alloc: allocates a chunk of memory.
 // - Free: frees a chunk of memory allocated with Alloc.
 
Index: coregrind/m_oset.c
===================================================================
--- coregrind/m_oset.c  (revision 7273)
+++ coregrind/m_oset.c  (working copy)
@@ -175,7 +175,15 @@
 // Compare the first word of each element.  Inlining is *crucial*.
 static inline Word fast_cmp(void* k, AvlNode* n)
 {
-   return ( *(Word*)k - *(Word*)elem_of_node(n) );
+   Word w1 = *(Word*)k;
+   Word w2 = *(Word*)elem_of_node(n);
+   // In previous versions, we tried to do this faster by doing
+   // "return w1 - w2".  But it didn't always work, due to the carry bit
+   // when the subtraction overflowed(?)  The branching version is slightly
+   // slows, but safer and easier to understand.
+   if (w1 > w2) return  1;
+   if (w1 < w2) return -1;
+   return 0;
 }
 
 // Compare a key and an element.  Inlining is *crucial*.
@@ -490,22 +498,23 @@
       while (True) {
          if (curr == NULL) return NULL;
          cmpres = slow_cmp(t, k, curr);
-         if (cmpres < 0) curr = curr->left;  else
-         if (cmpres > 0) curr = curr->right; else
-         return curr;
+         if      (cmpres < 0) curr = curr->left;
+         else if (cmpres > 0) curr = curr->right;
+         else return curr;
       }
    } else {
       // Fast-track special case.  We use the no-check version of
       // elem_of_node because it saves about 10% on lookup time.  This
       // shouldn't be very dangerous because each node will have been
       // checked on insertion.
-      Word kk = *(Word*)k;
+      Word w1 = *(Word*)k;
+      Word w2;
       while (True) {
          if (curr == NULL) return NULL;
-         cmpres = kk - *(Word*)elem_of_node_no_check(curr);
-         if (cmpres < 0) curr = curr->left;  else
-         if (cmpres > 0) curr = curr->right; else
-         return curr;
+         w2 = *(Word*)elem_of_node_no_check(curr);
+         if      (w1 < w2) curr = curr->left;
+         else if (w1 > w2) curr = curr->right;
+         else return curr;
       }
    }
 }
-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
Valgrind-developers mailing list
Valgrind-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/valgrind-developers

Reply via email to