LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 23180 - Conditional jump or move depends on uninitialised value
Summary: Conditional jump or move depends on uninitialised value
Status: RESOLVED INVALID
Alias: None
Product: new-bugs
Classification: Unclassified
Component: new bugs (show other bugs)
Version: 3.5
Hardware: PC Linux
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-04-09 16:42 PDT by Eric Youngblut
Modified: 2018-06-12 07:58 PDT (History)
5 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Youngblut 2015-04-09 16:42:22 PDT
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).
Comment 1 Eric Youngblut 2015-04-09 18:21:45 PDT
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!
Comment 2 Nick Lewycky 2015-04-09 18:25:26 PDT
Yes, I was just writing to say that. Can I interest you in clang -fsanitize=memory which doesn't have these false positives? :)
Comment 3 David Majnemer 2015-04-09 19:05:12 PDT
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.