Change the behaviour of --partial-loads-ok=yes to avoid false
negatives, by marking the V bits that come from out of range parts of
the access as undefined; and hence any use of them leads to an value
error.  Prior to this they were marked as defined and could be used
without error.

Behaviour of --partial-loads-ok=no (the default case) is unchanged.

Also add some testing thereof.

Fixes #294523.  Modified version of a patch and testcase by Patrick
J. LoPresti (lopresti@gmail.com).



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12430 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/tests/test-plo.c b/memcheck/tests/test-plo.c
new file mode 100644
index 0000000..9ce667a
--- /dev/null
+++ b/memcheck/tests/test-plo.c
@@ -0,0 +1,86 @@
+#include <malloc.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef  unsigned long long int  ULong;
+typedef  unsigned long int       UWord;
+
+__attribute__((noinline))
+static int my_ffsll ( ULong x )
+{
+   int i;
+   for (i = 0; i < 64; i++) {
+      if ((x & 1ULL) == 1ULL)
+         break;
+      x >>= 1;
+   }
+   return i+1;
+}
+
+/* Find length of string, assuming it is aligned and shorter than 8
+   characters.  Little-endian only. */
+__attribute__((noinline))
+static int aligned_strlen(char *s)
+{
+    /* This is for 64-bit platforms */
+    assert(sizeof(ULong) == 8);
+    /* ..and only works for aligned input */
+    assert(((unsigned long)s & 0x7) == 0);
+
+    /* read 8 bytes */
+    ULong val = *(ULong*)s;
+    /* Subtract one from each byte */
+    ULong val2 = val - 0x0101010101010101ULL;
+    /* Find lowest byte whose high bit changed */
+    val2 ^= val;
+    val2 &= 0x8080808080808080ULL;
+
+    return (my_ffsll(val2) / 8) - 1;
+}
+
+__attribute__((noinline)) void foo ( int x )
+{
+   __asm__ __volatile__("":::"memory");
+}
+
+int
+main(int argc, char *argv[])
+{
+    char *buf = memalign(8, 5);
+    buf[0] = 'a';
+    buf[1] = 'b';
+    buf[2] = 'c';
+    buf[3] = 'd';
+    buf[4] = '\0';
+
+    /* --partial-loads-ok=no:  expect addr error (here) */
+    /* --partial-loads-ok=yes: expect no error */
+    if (aligned_strlen(buf) == 4)
+        foo(44);
+
+    /* --partial-loads-ok=no:  expect addr error (here) */
+    /* --partial-loads-ok=yes: expect value error (in my_ffsll) */
+    buf[4] = 'x';
+    if (aligned_strlen(buf) == 0)
+        foo(37);
+
+    free(buf);
+
+    /* Also, we need to check that a completely out-of-range,
+       word-sized load gives an addressing error regardless of the
+       start of --partial-loads-ok=.  *And* that the resulting
+       value is completely defined. */
+    UWord* words = malloc(3 * sizeof(UWord));
+    free(words);
+
+    /* Should ALWAYS give an addr error. */
+    UWord  w     = words[1];
+
+    /* Should NEVER give an error (you might expect a value one, but no.) */
+    if (w == 0x31415927) {
+       fprintf(stderr,
+               "Elvis is alive and well and living in Milton Keynes.\n");
+    }
+
+    return 0;
+}