Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does GCC only sometimes detect the use of a variable before its initialization? [duplicate]

Tags:

c

gcc

gcc-warning

I was reading some code from a book, when I decided to make a change to see what the uninitialized value of sec would be before the while statement:

#include<stdio.h>

#define S_TO_M 60

int main(void)
{
    int sec,min,left;

    printf("This program converts seconds to minutes and ");
    printf("seconds. \n");
    printf("Just enter the number of seconds. \n");
    printf("Enter 0 to end the program. \n");
    printf("sec = %d\n",sec);
    while(sec > 0)
    {
        scanf("%d",&sec);
        min = sec/S_TO_M;
        left = sec % S_TO_M;
        printf("%d sec is %d min, %d sec. \n",sec,min,left);
        printf("Next input?\n");
    }
    printf("Bye!\n");

    return 0;
}

This compiles under GCC with no warnings, even though sec is uninitialized at that point, and I get a value of 32767:

$ gcc -Wall test.c
$ ./a.out 
This program converts seconds to minutes and seconds. 
Just enter the number of seconds. 
Enter 0 to end the program. 
sec = 32767

But when I comment out the while statement:

#include<stdio.h>

#define S_TO_M 60

int main(void)
{
    int sec;
    //min,left;

    printf("This program converts seconds to minutes and ");
    printf("seconds. \n");
    printf("Just enter the number of seconds. \n");
    printf("Enter 0 to end the program. \n");
    printf("sec = %d\n",sec);
    /*
    while(sec > 0)
    {
        scanf("%d",&sec);
        min = sec/S_TO_M;
        left = sec % S_TO_M;
        printf("%d sec is %d min, %d sec. \n",sec,min,left);
        printf("Next input?\n");
    }
    */
    printf("Bye!\n");

    return 0;
}

Now GCC issues a warning and sec ends up being zero:

$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:12:8: warning: ‘sec’ is used uninitialized in this function[-Wuninitialized]
printf("sec = %d\n",sec);
    ^
$ ./a.out
This program converts seconds to mintutes and seconds. 
Just enter the number of seconds. 
Enter 0 to end the program. 
sec = 0
Bye!

Why did the warning show up the second time but not the first time?

like image 593
tiancantudou Avatar asked Mar 28 '15 05:03

tiancantudou


People also ask

What happens if we use an uninitialized variable in C?

The code uses a variable that has not been initialized, leading to unpredictable or unintended results. In some languages such as C and C++, stack variables are not initialized by default. They generally contain junk data with the contents of stack memory before the function was invoked.

Does C automatically initialize variables?

In C and C++, local variables aren't initialized by default. Uninitialized variables can contain any value, and their use leads to undefined behavior.

When a variable is only declared and not initialized in C then the value stored in it is?

When we declare a variable without initializing it, then it just stores some garbage value or zero value. But if we assign some value to it, then it will be overwritten with the new value.

Does c++ automatically initialize variables to 0?

Unlike some programming languages, C/C++ does not initialize most variables to a given value (such as zero) automatically. Thus when a variable is given a memory address to use to store data, the default value of that variable is whatever (garbage) value happens to already be in that memory address!


2 Answers

Apparently gcc has a long running problem with false negatives with this option see this bug report: Bug 18501 - [4.8/4.9/5 Regression] Missing 'used uninitialized' warning (CCP) and the long list of duplicates:

Duplicates: 30542 30575 30856 33327 36814 37148 38945 39113 40469 42724 42884 45493 46684 46853 47623 48414 48643 49971 56972 57629 58323 58890 59225 60444

Note from comment towards the end, we can see this has been an ongoing issue for over ten years:

This year will be the 10 year anniversary of this bug. We should order cake!

Note, if you remove the:

scanf("%d",&sec);

you will also receive a warning, Marc Glisse also points out removing the first four printf also works as well (see it live). I don't see a similar example in the duplicates but not sure it is work adding yet another bug report for this.

Also see Better Uninitialized Warnings which says:

GCC has the ability to warn the user about using the value of a uninitialized variable. Such value is undefined and it is never useful. It is not even useful as a random value, since it rarely is a random value. Unfortunately, detecting when the use of an uninitialized variable is equivalent, in the general case, to solving the halting problem. GCC tries to detect some instances by using the information gathered by optimisers and warns about them when the option -Wuninitialized is given in the command line. There are a number of perceived shortcomings in current implementation. First, it only works when optimisation is enabled through -O1, -O2 or -O3. Second, the set of false positives or negatives varies according to the optimisations enabled. This also causes high variability of the warnings reported when optimisations are added or modified between releases.

A side note, clang seems to catch this case just fine (see live example):

 warning: variable 'sec' is uninitialized when used here [-Wuninitialized]
printf("sec = %d\n",sec);
                    ^~~

As I note in a comment below at least this case seems to be fixed in gcc 5.0.

like image 119
Shafik Yaghmour Avatar answered Oct 14 '22 16:10

Shafik Yaghmour


With this line:

scanf("%d",&sec);

GCC knows that you initialize sec somewhere in your function.

As a separate step, GCC can do flow analysis to figure out whether you initialize sec before using it. Unfortunately, GCC will not always do the flow analysis you want, or even do flow analysis at all. Sometimes the flow analyis is done at a stage where the other information is not available. So, you cannot count on GCC to figure it out.

Other compilers will figure it out. For example,

~ $ clang-3.7 -c -Wall -Wextra -O2 ex.c                      
ex.c:11:25: warning: variable 'sec' is uninitialized when used here
      [-Wuninitialized]
    printf("sec = %d\n",sec);
                        ^~~
ex.c:5:12: note: initialize the variable 'sec' to silence this warning
    int sec,min,left;
           ^
            = 0
1 warning generated.

It just so happens that GCC is very bad at detecting these errors.

like image 41
Dietrich Epp Avatar answered Oct 14 '22 17:10

Dietrich Epp