Incorporate horrible hack to workaround problem of emitting bogus
uninit-value errors on code with inlined strlen() et al from gcc-3.1
and above.

MERGE TO STABLE


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1213 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/docs/manual.html b/memcheck/docs/manual.html
index c2122f3..2847607 100644
--- a/memcheck/docs/manual.html
+++ b/memcheck/docs/manual.html
@@ -583,6 +583,20 @@
       in g++-3.0.4.
       </li><br><p>
 
+  <li><code>--avoid-strlen-errors=yes</code> [default]<br>
+      <code>--avoid-strlen-errors=no</code> <p>When enabled, valgrind
+      inspects each basic block it instruments for some tell-tale
+      literals (0xFEFEFEFF, 0x80808080, 0x00008080) which suggest
+      that this block is part of an inlined strlen() function.  In
+      many cases such functions cause spurious uninitialised-value
+      errors to be reported -- their code is too clever for the
+      instrumentation scheme.  This horrible hack works around the
+      problem, at the expense of hiding any genuine
+      uninitialised-value errors which might appear ine such blocks.
+      It is enabled by default because it is needed to get sensible
+      behaviour on code compiled by gcc-3.1 and above.
+      </li><br><p>
+
   <li><code>--error-limit=yes</code> [default]<br>
       <code>--error-limit=no</code> <p>When enabled, valgrind stops
       reporting errors after 30000 in total, or 300 different ones,
diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h
index e25dedb..2f9c905 100644
--- a/memcheck/mc_include.h
+++ b/memcheck/mc_include.h
@@ -145,6 +145,10 @@
 /* DEBUG: clean up instrumented code?  default: YES */
 extern Bool SK_(clo_cleanup);
 
+/* When instrumenting, omit some checks if tell-tale literals for
+   inlined strlen() are visible in the basic block.  default: YES */
+extern Bool SK_(clo_avoid_strlen_errors);
+
 
 /*------------------------------------------------------------*/
 /*--- Functions                                            ---*/
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index ef9dfc4..c2398db 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -57,6 +57,8 @@
 Bool  SK_(clo_workaround_gcc296_bugs) = False;
 Bool  SK_(clo_check_addrVs)           = True;
 Bool  SK_(clo_cleanup)                = True;
+Bool  SK_(clo_avoid_strlen_errors)    = True;
+
 
 /*------------------------------------------------------------*/
 /*--- Profiling events                                     ---*/
@@ -2318,6 +2320,11 @@
    else if (STREQ(arg, "--cleanup=no"))
       SK_(clo_cleanup) = False;
 
+   else if (STREQ(arg, "--avoid-strlen-errors=yes"))
+      SK_(clo_avoid_strlen_errors) = True;
+   else if (STREQ(arg, "--avoid-strlen-errors=no"))
+      SK_(clo_avoid_strlen_errors) = False;
+
    else
       return False;
 
@@ -2340,7 +2347,8 @@
 "    --check-addrVs=no|yes     experimental lighterweight checking? [yes]\n"
 "                              yes == Valgrind's original behaviour\n"
 "\n"
-"    --cleanup=no|yes          improve after instrumentation? [yes]\n";
+"    --cleanup=no|yes          improve after instrumentation? [yes]\n"
+"    --avoid-strlen-errors=no|yes  suppress errs from inlined strlen [yes]\n";
 }
 
 
diff --git a/memcheck/mc_translate.c b/memcheck/mc_translate.c
index 88f34ab..f81bde3 100644
--- a/memcheck/mc_translate.c
+++ b/memcheck/mc_translate.c
@@ -498,9 +498,43 @@
    Int         i, j;
    UInstr*     u_in;
    Int         qs, qd, qt, qtt;
+   Bool        bogusLiterals;
    cb = VG_(alloc_UCodeBlock)();
    cb->nextTemp = cb_in->nextTemp;
 
+   /* Scan the block to look for bogus literals.  These are magic
+      numbers which particularly appear in hand-optimised / inlined
+      implementations of strlen() et al which cause so much trouble
+      (spurious reports of uninit-var uses).  Purpose of this horrible
+      hack is to disable some checks any such literals are present in
+      this basic block. */
+   bogusLiterals = False;
+
+   if (SK_(clo_avoid_strlen_errors)) {
+      for (i = 0; i < cb_in->used; i++) {
+         u_in = &cb_in->instrs[i];
+         switch (u_in->opcode) {
+            case ADD: case SUB: case MOV: 
+               if (u_in->size == 4 && u_in->tag1 == Literal)
+                  goto literal;
+               break;
+            case LEA1: 
+               sk_assert(u_in->size == 4);
+               goto literal;
+            default: 
+               break;
+         }     
+         continue;
+        literal:
+         if (u_in->lit32 == 0xFEFEFEFF ||
+             u_in->lit32 == 0x80808080 ||
+             u_in->lit32 == 0x00008080) {
+            bogusLiterals = True;
+            break;
+         }
+      }
+   }
+
    for (i = 0; i < cb_in->used; i++) {
       qs = qd = qt = qtt = INVALID_TEMPREG;
       u_in = &cb_in->instrs[i];
@@ -1003,7 +1037,12 @@
             if (u_in->cond != CondAlways) {
                sk_assert(u_in->flags_r != FlagsEmpty);
                qt = create_GETVF(cb, 0);
-               uInstr1(cb, TESTV, 0, TempReg, qt);
+               if (/* HACK */ bogusLiterals) {
+                  if (0) 
+                     VG_(printf)("ignore TESTV due to bogus literal\n");
+               } else {
+                  uInstr1(cb, TESTV, 0, TempReg, qt);
+               }
                /* qt should never be referred to again.  Nevertheless
                   ... */
                uInstr1(cb, SETV, 0, TempReg, qt);