Valgrind found a bug and we confirmed it by reading the generated assembly code. ======== file1.c ======== #include <stdio.h> #include <stdbool.h> bool pop_if_contains(int *value); static int pop_or_default(int default_value) { int value; return pop_if_contains(&value) ? value : default_value; } int main(void) { int value = pop_or_default(1001); if (value != 1001) puts("error"); } ======== file2.c ======== #include <stdbool.h> bool pop_if_contains(int *value) { return false; } ======== clang -Os -fno-omit-frame-pointer file1.c file2.c valgrind ./a.out ==24488== Memcheck, a memory error detector ==24488== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==24488== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==24488== Command: ./a.out ==24488== ==24488== Conditional jump or move depends on uninitialised value(s) ==24488== at 0x400548: main (in /home/ericy/a.out) ==24488== ==24488== ==24488== HEAP SUMMARY: ==24488== in use at exit: 0 bytes in 0 blocks ==24488== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==24488== ==24488== All heap blocks were freed -- no leaks are possible ==24488== ==24488== For counts of detected and suppressed errors, rerun with: -v ==24488== Use --track-origins=yes to see where uninitialised values come from ==24488== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1) (gdb) disassemble main Dump of assembler code for function main: 0x0000000000400530 <+0>: push %rbp 0x0000000000400531 <+1>: mov %rsp,%rbp 0x0000000000400534 <+4>: sub $0x10,%rsp 0x0000000000400538 <+8>: lea -0x4(%rbp),%rdi 0x000000000040053c <+12>: callq 0x400560 <pop_if_contains> 0x0000000000400541 <+17>: cmpl $0x3e9,-0x4(%rbp) 0x0000000000400548 <+24>: je 0x400558 <main+40> 0x000000000040054a <+26>: xor $0x1,%al 0x000000000040054c <+28>: jne 0x400558 <main+40> 0x000000000040054e <+30>: mov $0x4005f4,%edi 0x0000000000400553 <+35>: callq 0x400410 <puts@plt> 0x0000000000400558 <+40>: xor %eax,%eax 0x000000000040055a <+42>: add $0x10,%rsp 0x000000000040055e <+46>: pop %rbp 0x000000000040055f <+47>: retq It seems that the compiler has erroneously reordered the comparisons. The cmpl/je is the "if (value != 1001)" and the xor/jne is the ? operator, but they're in the wrong order. Found at Qumulo, Inc. (qumulo.com).
This isn't actually a bug. It seems LLVM is taking advantage of the fact that it doesn't matter whether the function returns true or false as long as the expected value (1001) is already present in the memory location. It technically doesn't matter whether the function wrote it or whether it was already present. But it does freak Valgrind (and humans) out!
Yes, I was just writing to say that. Can I interest you in clang -fsanitize=memory which doesn't have these false positives? :)
There is no bug to fix, LLVM is free to compute whatever values based off of uninitialized memory it likes so long as those speculative computations never effect the program's behavior.