Bug 36550 - Wrong "may be used uninitialized" warning (conditional PHIs)
Summary: Wrong "may be used uninitialized" warning (conditional PHIs)
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.1.2
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
: 27289 38037 39088 39133 (view as bug list)
Depends on:
Blocks: Wuninitialized 20968
  Show dependency treegraph
 
Reported: 2008-06-17 09:53 UTC by Bernhard Reutner-Fischer
Modified: 2011-04-17 22:17 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-08-18 17:29:25


Attachments
Very simple testcase (107 bytes, text/plain)
2011-04-17 22:17 UTC, Vincent Riviere
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Bernhard Reutner-Fischer 2008-06-17 09:53:07 UTC
Yet another one. It behaves the same for 4.1.2 and current trunk.

$ gcc -Os -Wuninitialized -c uninit-J.c
uninit-J.c: In function 'pr':
uninit-J.c:7: warning: 'bug' may be used uninitialized in this function

$ cat uninit-J.c
/* { dg-do compile } */
/* { dg-options "-Os -Wuninitialized" } */
void bail(void) __attribute__((noreturn));
unsigned check(void);
int pr(char**argv)
{
	char *bug;
	if (check()) {
		if (*argv)
			bug = *++argv;
	} else {
		bug = *argv++;
		if (!*argv)
			bail();
	}
	/* now bug is set except if (check() && !*argv) */
	if (check()) {
		if (!*argv)
			return 0;
	}
	/* if we ever get here then bug is set */
	return *bug != 'X';
}
Comment 1 Serge Belyshev 2008-06-17 10:40:46 UTC
check() can return 1 on the first call and 0 on the second and if *argv is NULL then then "bug" will be used uninitialized.
Comment 2 Bernhard Reutner-Fischer 2008-06-17 10:46:55 UTC
(In reply to comment #1)
> check() can return 1 on the first call and 0 on the second and if *argv is NULL
> then then "bug" will be used uninitialized.

right, but this doesn't matter here. Better testcase:

/* { dg-do compile } */
/* { dg-options "-Os -Wuninitialized" } */
void bail(void) __attribute__((noreturn));
unsigned once(void);
int pr(char**argv)
{
	char *bug;
	unsigned check = once();
	if (check) {
		if (*argv)
			bug = *++argv;
	} else {
		bug = *argv++;
		if (!*argv)
			bail();
	}
	/* now bug is set except if (check && !*argv) */
	if (check) {
		if (!*argv)
			return 0;
	}
	/* if we ever get here then bug is set */
	return *bug != 'X';
}
Comment 3 Andrew Pinski 2008-06-17 13:24:53 UTC
This really needs conditional phis so ...
Comment 4 Andrew Pinski 2008-11-06 21:11:19 UTC
*** Bug 38037 has been marked as a duplicate of this bug. ***
Comment 5 Andrew Pinski 2009-02-04 00:09:08 UTC
*** Bug 39088 has been marked as a duplicate of this bug. ***
Comment 6 Manuel López-Ibáñez 2009-02-07 15:05:49 UTC
*** Bug 27289 has been marked as a duplicate of this bug. ***
Comment 7 Manuel López-Ibáñez 2009-02-12 11:22:38 UTC
*** Bug 39133 has been marked as a duplicate of this bug. ***
Comment 8 Manuel López-Ibáñez 2009-02-12 11:45:27 UTC
I added this as Problem 5 in the wiki:

http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
Comment 9 Corin 2009-02-12 21:53:26 UTC
I do not really understand problem 5 for the case when the only dependancy for the code-path check is a local variable. In this case the value cannot be change by any other code than existing between the two checks, so this case should be handled reliable for sure. Of course this is not possible with global oder class variables which might be affected by some other thread.
Comment 10 Manuel López-Ibáñez 2009-02-12 22:05:58 UTC
(In reply to comment #9)
> I do not really understand problem 5 for the case when the only dependancy for
> the code-path check is a local variable. In this case the value cannot be
> change by any other code than existing between the two checks, so this case
> should be handled reliable for sure.

Should? I guess you meant "could". Because it is obviously not handled right now at the moment of warning.

That page simply lists causes, testcases and possible solutions for existing problems. As always, contributions are welcome.
Comment 11 davidxl 2010-04-20 23:55:09 UTC
(In reply to comment #2)
> (In reply to comment #1)
> > check() can return 1 on the first call and 0 on the second and if *argv is NULL
> > then then "bug" will be used uninitialized.
> 
> right, but this doesn't matter here. Better testcase:
> 
> /* { dg-do compile } */
> /* { dg-options "-Os -Wuninitialized" } */
> void bail(void) __attribute__((noreturn));
> unsigned once(void);
> int pr(char**argv)
> {
>         char *bug;
>         unsigned check = once();
>         if (check) {
>                 if (*argv)
>                         bug = *++argv;
>         } else {
>                 bug = *argv++;
>                 if (!*argv)
>                         bail();
>         }
>         /* now bug is set except if (check && !*argv) */
>         if (check) {
>                 if (!*argv)
>                         return 0;
>         }
>         /* if we ever get here then bug is set */
>         return *bug != 'X';
> }
> 


The example is a little tricky for the compiler to reason because of the '++argv'. Predicate analysis (http://gcc.gnu.org/ml/gcc-patches/2010-04/msg00706.html -- with additional fix to a never return handling) will catch the following case (while the trunk gcc does not):


void bail(void) __attribute__((noreturn));
int foo(void);
unsigned once(void);
int pr(char**argv)
{
        char *bug;
        unsigned check = once();
	char * a = *argv;
        if (check) {
                if (a)
                        bug = *++argv;
        } else {
                bug = *argv++;
                if (!*argv)
                        bail();
        }

	if (foo ())
	  once();

        /* now bug is set except if (check && !*argv) */
        if (check) {
                if (!a || !*argv)
                        return 0;
        }
        /* if we ever get here then bug is set */
        return *bug != 'X';
}

Comment 12 Vincent Riviere 2011-04-17 22:17:35 UTC
Created attachment 24023 [details]
Very simple testcase

I hit the "may be used uninitialized in this function" bug when compiling this small testcase. I think it is the same as the bug described here.

$ gcc -c bug.c -Os -Wuninitialized
bug.c: In function 'f':
bug.c:9: warning: 'b' may be used uninitialized in this function

This happens with:
- GCC 4.4.5 (Debian 4.4.5-8) for the target i486-linux-gnu
- GCC 4.5.2 for the target m68k-atari-mint