llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.43k stars 11.75k forks source link

Missing -Wuninitialized warning with some gotos #43062

Closed 70e8c5c0-afb3-4429-baaf-906675eb77bb closed 4 years ago

70e8c5c0-afb3-4429-baaf-906675eb77bb commented 4 years ago
Bugzilla Link 43717
Resolution INVALID
Resolved on Oct 18, 2019 19:50
Version trunk
OS Linux
CC @zygoloid

Extended Description

Using the following

#include <stdlib.h>
#include <stdio.h>

int foo;

int main() {
        int status;

        if (foo) {
                goto error;
        }

        goto end;

error:
        status = 1;

end:
        if (foo) {
                status = 1;
        }

        return status;
}

Unless I'm missing something, I think there's a quite obvious path (when foo is false) where status is used without being initialized. However, I don't get a warning with:

$ clang-10 ~/build/babeltrace-clang/test.c -Werror -Wuninitialized -Wsometimes-uninitialized

Removing either condition gives me -Wsometimes-uninitialized diagnostic, as expected.

$ clang-10 --version clang version 10.0.0-svn375132-1~exp1+0~20191017164644.1263~1.gbpd72b70 (trunk) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin

70e8c5c0-afb3-4429-baaf-906675eb77bb commented 4 years ago

Ok, thanks for explaining the nuances between the different flavors of uninitialized warnings.

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 4 years ago

This is working as intended.

-Wuninitialized warns on cases where a particular use of a variable is only reachable in cases where the variable is uninitialized. (So either that use of the variable is unreachable, or you have a use-uninitialized bug.)

-Wsometimes-uninitialized warns on cases where a particular branch always results in an uninitialized use whenever it's taken. (So either that branch can never be taken in that direction, or you have a use-uninitialized bug.)

Under the assumption that you have no dead code, both warnings have zero false positives.

If instead you want a warning with fewer false negatives (but that instead has false positives), you can use -Wconditional-uninitialized. That will warn whenever we see a use of a variable and we can find any path to that variable that didn't initialize it. (This has false positives if the path that we find is actually impossible -- for instance, if it contains two branches on the same value and requires them to go in different directions.)

-Wconditional-uninitialized does warn on this code:

:20:16: warning: variable 'status' may be uninitialized when used here [-Wconditional-uninitialized] return status; ^~~~~~ :4:19: note: initialize the variable 'status' to silence this warning int status; ^ = 0 (You can also use -Weverything to find out whether clang has a warning for a particular construct.)