17

I am experiencing a very strange issue using gcc-4.7 (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2. I am unable to compile the following valid code without a warning:

extern void dostuff(void);

int test(int arg1, int arg2)
{
    int ret;

    if (arg1) ret = arg2 ? 1 : 2;

    dostuff();

    if (arg1) return ret;

    return 0;
}

Compile options and output:

$ gcc-4.7 -o test.o -c -Os test.c -Wall
test.c: In function ‘test’:
test.c:5:6: warning: ‘ret’ may be used uninitialized in this function [-Wmaybe-uninitialized]

However, the following code compiles with no warning (albeit to slightly less efficient assembly):

extern void dostuff(void);

int test(int arg1, int arg2)
{
    int ret;

    if (arg1 && arg2) ret = 1;
    if (arg1 && !arg2) ret = 2;

    dostuff();

    if (arg1) return ret;

    return 0;
}

I am somewhat stuck and am considering this a compiler bug. Any thoughts?

7
  • You probably mean ret == arg2 ? 1 : 2;?? Commented Jan 3, 2013 at 4:12
  • 1
    No, the syntax is fine. I mean return 0 if arg1=0, arg2=0, return 1 if arg1=1, arg2=1, return 2 if arg1=1, arg2=0. This snippet is a simplified case of a much larger issue I'm having. Commented Jan 3, 2013 at 4:14
  • Making ret volatile also resolves the issue, but isn't really ideal. Commented Jan 3, 2013 at 4:15
  • 2
    Thanks Alok, but possibly this constructed example will produce misguided solutions. Code density is extremely important here, and in the actual function ret is a large array which I don't want to initialize if it is not used. Looking at my first program, ret is indeed never used uninitialized, so the warning is incorrect, no? Commented Jan 3, 2013 at 4:23
  • 1
    @AlokSave The code above will either initialize and return ret or it will not initialize but then also never use ret at all. Your objection is incorrect, the code as shown above will for sure never access ret before it is initialized, an explicit zero initializing is not needed, and if the compiler claims anything else, it's broken. Commented Dec 24, 2020 at 20:41

2 Answers 2

22

Indeed this is a known problem in gcc.
gcc is notorious for reporting incorrect uninitialized variables.
The shortcomings have been duly noted and there is a initiative to overcome the shortcomings:
Better Uninitialized Warnings:

The GNU Compiler Collection warns about the use of uninitialized variables with the option -Wuninitialized. However, the current implementation has some perceived shortcomings. On one hand, some users would like more verbose and consistent warnings. On the other hand, some users would like to get as few warnings as possible. The goal of this project is to implement both possibilities while at the same time improving the current capabilities.

The initiative aims at providing better warnings and it quotes a example case similar as your case. The relevant portion being:

What an user understands as a false positive may be different for the particular user. Some users are interested in cases that are hidden because of actions of the optimizers combined with the current environment. However, many users aren't, since that case is hidden because it cannot arise in the compiled code. The canonical example is

int x;
if (f ())
     x = 3;
return x;

where 'f' always return non-zero for the current environment, and thus, it may be optimized away. Here, a group of users would like to get an uninitialized warning since 'f' may return zero when compiled elsewhere. Yet, other group of users would consider spurious a warning about a situation that cannot arise in the executable being compiled.

Sign up to request clarification or add additional context in comments.

1 Comment

On one hand, some users would like -pedantic and -Werror. So these users have to turn off Wuninitialized for gcc 4, 5, 6, 7. It is still broken in 2018.
3

Not sure if gcc has been fixed in the meantime. If not, you may want to try clang. It's the far better compiler IMHO and it does much better code analyzes.

Just because some comments claim the compiler is right, ret may be used uninitialized, here's the proof of the contrary. The code

int test(int arg1, int arg2)
{
    int ret;
    if (arg1) ret = arg2 ? 1 : 2;
    dostuff();
    if (arg1) return ret;
    return 0;
}

can easily be transformed to the following code by just combining the two identical if statements into one:

int test(int arg1, int arg2)
{
    if (arg1) {
        int ret = arg2 ? 1 : 2;
        dostuff();
        return ret;
    }
    dostuff();
    return 0;
}

This is equivalent code and now it should be obvious, that ret can never be used uninitialized. The compiler is wrong, the warning is pointless.

But then again, the code can be further simplified:

int test(int arg1, int arg2)
{
    dostuff();
    return (arg1 ? (arg2 ? 1 : 2) : 0);
}

Problem solved, ret is gone.

3 Comments

'It's the far better compiler IMHO and it does much better code analyzes' - and it's known for better error messages, but in my tests for my specific application, the code was 10..15% slower.
@MichałLeon Can you provide more details about this? Like what kind of specific application and what build platform, build target, and build options? The LLVM devs are always glad when people make them aware of issues like that, as usually that is caused by edge cases that require just some fine tuning. If you compare the performance of Clang 3.8 vs GCC 5.3.1, GCC was still ahead most of the time. Comparing Clang 8 to GCC 8.3, there is hardly any difference left. And testing with latest Clang and GCC, most of the time Clang wins on my system.
I noticed that Qt no longer provides kits compiled with LLVM, so unless someone knows what was the last Qt version with LLVM, I won't be able to provide a comparison. If you happen to know this, let me know, and I'll provide a comparison. Please note that I did not claim LLVM to be universally slower - I specifically wrote that my project was 10..15% slower.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.