Summary: | asm shifts cause false positive "Conditional jump or move depends on uninitialised value" | ||
---|---|---|---|
Product: | [Developer tools] valgrind | Reporter: | Markus Trippelsdorf <octoploid> |
Component: | memcheck | Assignee: | Julian Seward <jseward> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | ivosh, jakub |
Priority: | NOR | ||
Version: | 3.14 SVN | ||
Target Milestone: | --- | ||
Platform: | Other | ||
OS: | Linux | ||
Latest Commit: | Version Fixed In: |
Description
Markus Trippelsdorf
2017-12-10 10:45:34 UTC
But: int foo (int x) { asm volatile ("sarl $16, %0; js 1f; incl %0; 1:" : "+r" (x)); return x; } int bar (int x) { asm volatile ("sarl $16, %0; testl %0, %0; js 1f; incl %0; 1:" : "+r" (x)); return x; } int main () { __builtin_printf ("%x %x\n", foo (0x87654321), bar (0x87654321)); __builtin_printf ("%x %x\n", foo (0x12345678), bar (0x12345678)); return 0; } doesn't show any difference when running without and with valgrind. (In reply to Markus Trippelsdorf from comment #0) > Running gcc trunk under valgrind produces many false positives, e.g.: Please provide a simple standalone reproducer. For example, could a part of update_costs_from_copies() be isolated to reproduce the problem? There is also a patch for Valgrind which makes it to spend some extra time to accurately track definedness: https://bugs.kde.org/show_bug.cgi?id=387664 Please could you try to build Valgrind with this patch and then run it with --expensive-definedness-checks=yes (or --expensive-definedness-checks=auto). (In reply to Ivo Raisr from comment #2) > (In reply to Markus Trippelsdorf from comment #0) > > Running gcc trunk under valgrind produces many false positives, e.g.: > > Please provide a simple standalone reproducer. For example, could a part of > update_costs_from_copies() be isolated to reproduce the problem? > > There is also a patch for Valgrind which makes it to spend some extra time > to accurately track definedness: > https://bugs.kde.org/show_bug.cgi?id=387664 > > Please could you try to build Valgrind with this patch and then run it with > --expensive-definedness-checks=yes (or --expensive-definedness-checks=auto). Your patch fixes the issue. Thanks. I will try to come up with a testcase tomorrow. (In reply to Markus Trippelsdorf from comment #3) > (In reply to Ivo Raisr from comment #2) > > (In reply to Markus Trippelsdorf from comment #0) > > > Running gcc trunk under valgrind produces many false positives, e.g.: > > > > Please provide a simple standalone reproducer. For example, could a part of > > update_costs_from_copies() be isolated to reproduce the problem? > > > > There is also a patch for Valgrind which makes it to spend some extra time > > to accurately track definedness: > > https://bugs.kde.org/show_bug.cgi?id=387664 > > > > Please could you try to build Valgrind with this patch and then run it with > > --expensive-definedness-checks=yes (or --expensive-definedness-checks=auto). > > Your patch fixes the issue. Thanks. Actually no. Trunk is fine without any patch at all (and without --expensive-definedness-checks=yes). So it looks like the issue is already fixed. It was fixed a few days ago by commit 8a2acb304db99c: amd64: add a spec rule for SHRL/SARL then CondS. gcc-8 has been seen to generate such things. Verified .. gcc version 8.0.0 20171210 runs clean on x86_64 linux when configured with --enable-valgrind-annotations, the trunk, and the https://bugs.kde.org/show_bug.cgi?id=387664 patch, which will land soon. I didn't try without the patch. I should note in passing, that I previously tried the 20171203 snapshot without --enable-valgrind-annotations, since I was not aware of it. I got a lot of complaints, all originating from sparseset_bit_p() in gcc/sparseset.h, because this deliberately does a comparison on undefined values. I fixed this using the patch below. I mention this because I am concerned that --enable-valgrind-annotations might "fix" the problem by zero-initialising various allocations that create memory used in sparseset_bit_p(). IMO that is the wrong solution, because it will "hide" any legitimate uninitialised values that would otherwise have been read from such allocations -- and so you reduce Memcheck's ability to detect errors in gcc. That said, this is only speculation -- I haven't actually checked what --enable-valgrind-annotations does. My fix follows. Clearly you'd actually want to ifdef the macro call so that this actually builds on targets that don't have <valgrind/memcheck.h>. --- gcc-8-20171203/gcc/sparseset.h~ 2017-01-01 13:07:43.000000000 +0100 +++ gcc-8-20171203/gcc/sparseset.h 2017-12-06 10:21:00.447480896 +0100 @@ -130,24 +130,27 @@ static inline SPARSESET_ELT_TYPE sparseset_size (sparseset s) { return s->size; } /* Return true if e is a member of the set S, otherwise return false. */ +#include <valgrind/memcheck.h> + static inline bool sparseset_bit_p (sparseset s, SPARSESET_ELT_TYPE e) { SPARSESET_ELT_TYPE idx; gcc_checking_assert (e < s->size); idx = s->sparse[e]; + VALGRIND_MAKE_MEM_DEFINED(&idx, sizeof(idx)); return idx < s->members && s->dense[idx] == e; } /* Low level insertion routine not meant for use outside of sparseset.[ch]. Assumes E is valid and not already a member of the set S. */ static inline void The ENABLE_VALGRIND_ANNOTATIONS logic is in gcc/system.h:1143. sparseset allocations are already handled in gcc/sparseset.c: 25 /* Allocate and clear a n_elms SparseSet. */ 26 27 sparseset 28 sparseset_alloc (SPARSESET_ELT_TYPE n_elms) 29 { 30 unsigned int n_bytes = sizeof (struct sparseset_def) 31 + ((n_elms - 1) * 2 * sizeof (SPARSESET_ELT_TYPE)); 32 33 sparseset set = XNEWVAR (struct sparseset_def, n_bytes); 34 35 /* Mark the sparseset as defined to silence some valgrind uninitialized 36 read errors when accessing set->sparse[n] when "n" is not, and never has 37 been, in the set. These uninitialized reads are expected, by design and 38 harmless. */ 39 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (set, n_bytes)); |