[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2

2018-09-15 Thread glisse at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #20 from Marc Glisse  ---
(In reply to Vincent Lefèvre from comment #18)
> OK, but then, this means that the first sentence of the
> -Wmaybe-uninitialized documentation is incorrect. That's probably the "there
> exists" that is problematic, because of the possible difference of what
> actually exists and what the compiler sees.

"There exists" is implicitly "in the internal representation at some specific
stage in the optimization process", not directly in the user's code. This
applies to any middle-end warning. If you want to suggest some clearer
documentation...

[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2

2018-09-15 Thread manu at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #19 from Manuel López-Ibáñez  ---
(In reply to Vincent Lefèvre from comment #18)
> OK, but then, this means that the first sentence of the
> -Wmaybe-uninitialized documentation is incorrect. That's probably the "there
> exists" that is problematic, because of the possible difference of what
> actually exists and what the compiler sees.

I don't disagree but a bug report about that will just linger forever without
any useful information. Sending a documentation patch and convincing the
middle-end reviewers will be more effective. 

Also, the same is true for any middle-end warning:
https://gcc.gnu.org/wiki/cauldron2018?action=AttachFile=get=Static_Analysis_in_GCC_Middle-End.pdf

[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2

2018-09-14 Thread vincent-gcc at vinc17 dot net
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #18 from Vincent Lefèvre  ---
OK, but then, this means that the first sentence of the -Wmaybe-uninitialized
documentation is incorrect. That's probably the "there exists" that is
problematic, because of the possible difference of what actually exists and
what the compiler sees.

[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2

2018-09-13 Thread manu at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

Manuel López-Ibáñez  changed:

   What|Removed |Added

 Status|UNCONFIRMED |RESOLVED
 Resolution|--- |INVALID

--- Comment #17 from Manuel López-Ibáñez  ---
I don't think this is a bug. GCC warns at higher levels because it can inline.
Doing more optimization at -O2 is a separate issue.

[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2

2016-09-03 Thread manu at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #16 from Manuel López-Ibáñez  ---
(In reply to Vincent Lefèvre from comment #15)
> Well, detecting uninitialized variables is equivalent to generating better
> code. See the following functions. If you want to be able to remove the i ==
> 0 test in the first one (making generated code better), you'll solve the
> warning problem in the second one.

Not really, the pass that generates better code may happen after the pass that
warns. And heuristics that generate better code often hide warnings: PR18501

Neither generating better code nor warning are exact methods. They rely on
heuristics. The warnings are even more sensitive, because the goal of the
compiler is to generate better code, not to produce accurate warnings, so
information that is useful for warning is not maintained throughout.

And then, there are heuristics such as not warning for f(), by assuming that
it will initialize c, that are implemented because they are more often right
than wrong, but they are sometimes wrong. When it can be established that they
were wrong (after inlining, for example), then warnings are given.

You seem to be assuming that

void g1(int *p);
int f1()
{
 int c;
 g1();
 return c; /* warn maybe-uninit */
}

int g2();
int f2()
{
 int c = g2();
 return c; /* warn maybe-uninit */
}
int h(int p)
{
 int c;
  if (p)
c = 1;
 return c; /* warn maybe-uninit */
}

are equivalent in terms of being maybe uninitialized, and all should either be
warned or not warned about. But in practice, f1() and f2() are most often a
false positive and h() is almost always a real bug.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread jakub at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

Jakub Jelinek jakub at gcc dot gnu.org changed:

   What|Removed |Added

 CC||jakub at gcc dot gnu.org

--- Comment #1 from Jakub Jelinek jakub at gcc dot gnu.org ---
I don't see anything strange on it, -Wmaybe-uninitialized is a middle-end
warning and as such very much depends on the optimizations, there is no
guarantee you get the same warnings between different optimization levels,
whether something is found as potentially uninitialized depends heavily e.g. on
inlining, tail recursion etc.  In this case at -O3 the function is first
inlined into itself a small amount of times.  I don't see anything wrong to
warn here, given that the variable indeed is not initialized in some code paths
(if fn2 returns zero).


[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread vincent-gcc at vinc17 dot net
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #2 from Vincent Lefèvre vincent-gcc at vinc17 dot net ---
Well, the code paths in question do not necessarily exist (you could say the
same thing with -O2, where the function is not inlined: there may be some code
paths for which fn1() doesn't initialize c).

Actually the number of maybe-uninitialized warnings should decrease when the
optimization level increases, because of additional knowledge, not the
opposite.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread jakub at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

Jakub Jelinek jakub at gcc dot gnu.org changed:

   What|Removed |Added

 Status|UNCONFIRMED |RESOLVED
 Resolution|--- |INVALID

--- Comment #3 from Jakub Jelinek jakub at gcc dot gnu.org ---
(In reply to Vincent Lefèvre from comment #2)
 Well, the code paths in question do not necessarily exist (you could say the
 same thing with -O2, where the function is not inlined: there may be some
 code paths for which fn1() doesn't initialize c).

The code path exists in the code, the fact that perhaps in your program such
code path is never taken doesn't mean it is undesirable to warn about it.
GCC has two kinds of warnings, the is uninitialized one where particular code,
if executed, will always use uninitialized value, and maybe uninitialized,
where it will use uninitialized value only conditionally.  That is the case
here.
 
 Actually the number of maybe-uninitialized warnings should decrease when
 the optimization level increases, because of additional knowledge, not the
 opposite.

No, usually with more inlining it increases and should.  When fn1 is not
inlined, GCC intentionally does not warn that c might be uninitialized because
maybe the function call could use the value or not set it unconditionally, that
would lead to so huge amount of false positives for the warning that nobody
would be willing to use the warning.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread rguenth at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #4 from Richard Biener rguenth at gcc dot gnu.org ---
(In reply to Jakub Jelinek from comment #3)
 (In reply to Vincent Lefèvre from comment #2)
  Well, the code paths in question do not necessarily exist (you could say the
  same thing with -O2, where the function is not inlined: there may be some
  code paths for which fn1() doesn't initialize c).
 
 The code path exists in the code, the fact that perhaps in your program such
 code path is never taken doesn't mean it is undesirable to warn about it.
 GCC has two kinds of warnings, the is uninitialized one where particular
 code, if executed, will always use uninitialized value, and maybe
 uninitialized, where it will use uninitialized value only conditionally. 
 That is the case here.

Where it of course still only assumes that the function is entered at all.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread vincent-gcc at vinc17 dot net
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #5 from Vincent Lefèvre vincent-gcc at vinc17 dot net ---
(In reply to Jakub Jelinek from comment #3)
 The code path exists in the code,

It exists *only* if fn2() can return 0. But the fact is that in the reality,
this can never happen (with the original non-reduced code, this can even be
proved).

 the fact that perhaps in your program such
 code path is never taken doesn't mean it is undesirable to warn about it.
 GCC has two kinds of warnings, the is uninitialized one where particular
 code, if executed, will always use uninitialized value, and maybe
 uninitialized, where it will use uninitialized value only conditionally. 
 That is the case here.

But in this case, the warning is missing with -O2.

 No, usually with more inlining it increases and should.  When fn1 is not
 inlined, GCC intentionally does not warn that c might be uninitialized
 because maybe the function call could use the value or not set it
 unconditionally, that would lead to so huge amount of false positives for
 the warning that nobody would be willing to use the warning.

This is the same problem with -O3: there is a false positive here. So, you have
to choose whether you want to avoid false positives or not.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread jakub at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #6 from Jakub Jelinek jakub at gcc dot gnu.org ---
How can the compiler know that fn2 never returns 0, without inlining (not in
this case), some attribute (not provided, gcc right now has returns_nonnull
attribute but that is only for pointers) or some interprocedural analysis)?
Of course, if you want zero false positives, the uninitialized warnings could
not exist, even if you do:
int
foo (void)
{
  int c;
  return c;
}
you could say that warning here is a false positive, because you might actually
never call that function.

For -O2 we don't warn, because then the compiler does see an opaque call that
might be initializing what the arguments points to, might not, but warning in
that case would just mean too many false positives as I've said before.
While for -O3, when it is inlined a few times, the compiler clearly sees code
paths where the value is uninitialized, and has nothing that would hint such
code paths are impossible.
Of course, if fn2 is guaranteed to return non-NULL, why do you even write if
(fn2 (a, 0)) *p1 = b; rather than just
fn2 (a, 0); *p1 = b; ?


[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread vincent-gcc at vinc17 dot net
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #7 from Vincent Lefèvre vincent-gcc at vinc17 dot net ---
(In reply to Jakub Jelinek from comment #6)
 How can the compiler know that fn2 never returns 0, without inlining (not in
 this case), some attribute (not provided, gcc right now has returns_nonnull
 attribute but that is only for pointers) or some interprocedural analysis)?

It doesn't know with -O3, but it doesn't know either with -O2 as well. That's
my point (see below).

 For -O2 we don't warn, because then the compiler does see an opaque call
 that might be initializing what the arguments points to, might not, but
 warning in that case would just mean too many false positives as I've said
 before.

I think it should. Or you should avoid the false positives with -O3 too.

 Of course, if fn2 is guaranteed to return non-NULL, why do you even write if
 (fn2 (a, 0)) *p1 = b; rather than just
 fn2 (a, 0); *p1 = b; ?

That's because of creduce. But it seems that I've managed to make the warning
disappear with both -O2 and -O3 even when it is clear that the value is not
initialized. More later...

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread vincent-gcc at vinc17 dot net
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

Vincent Lefèvre vincent-gcc at vinc17 dot net changed:

   What|Removed |Added

 Status|RESOLVED|UNCONFIRMED
 Resolution|INVALID |---

--- Comment #8 from Vincent Lefèvre vincent-gcc at vinc17 dot net ---
(In reply to Vincent Lefèvre from comment #5)
 It exists *only* if fn2() can return 0. But the fact is that in the reality,
 this can never happen (with the original non-reduced code, this can even be
 proved).

After an analysis of the MPFR code, it actually seems to be a bug in MPFR. So,
the problem is the missing warning with -O2.

The -Wmaybe-uninitialized rule given in the gcc man page is (for GCC 4.8):

  -Wmaybe-uninitialized
For an automatic variable, if there exists a path from the function
entry to a use of the variable that is initialized, but there exist
some other paths for which the variable is not initialized, the
compiler emits a warning if it cannot prove the uninitialized paths
are not executed at run time. [...]

This rule does *not* depend on the optimization level, except for the if it
cannot prove the uninitialized paths are not executed at run time part.
Indeed, the fact that a path exists or not is not something that depends on the
optimizations.

Concerning the if it cannot prove the uninitialized paths are not executed at
run time part, GCC should be able to prove more things with -O3 than with -O2,
meaning that -Wmaybe-uninitialized warnings could disappear with -O3 compared
to -O2, but generally not the opposite.

In the original example, GCC cannot prove anything about run time, so that
according to the gcc man page, one should get a warning whatever the
optimization level.

I've another example (similar to the MPFR code):

int fn3 (void);
void fn2 (int *p)
{
  if (fn3 ())
*p = 0;
}
int fn1 (void)
{
  int c;
  fn2 (c);
  return c;
}

GCC doesn't give any may be used uninitialized warning (whether -O2 or -O3 is
used). This is incorrect according to the above rule. BTW, for -O3, this is
surprising because it is similar to the original example.

I'm reopening the bug because the GCC behavior doesn't match the documentation.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread glisse at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #9 from Marc Glisse glisse at gcc dot gnu.org ---
(In reply to Vincent Lefèvre from comment #8)
 The -Wmaybe-uninitialized rule given in the gcc man page is (for GCC 4.8):
 
   -Wmaybe-uninitialized
 For an automatic variable, if there exists a path from the function
 entry to a use of the variable that is initialized, but there exist
 some other paths for which the variable is not initialized, the
 compiler emits a warning if it cannot prove the uninitialized paths
 are not executed at run time. [...]
 
 This rule does *not* depend on the optimization level, except for the if it
 cannot prove the uninitialized paths are not executed at run time part.
 Indeed, the fact that a path exists or not is not something that depends on
 the optimizations.

The definition of a function changes with inlining ;-)

 Concerning the if it cannot prove the uninitialized paths are not executed
 at run time part, GCC should be able to prove more things with -O3 than
 with -O2, meaning that -Wmaybe-uninitialized warnings could disappear with
 -O3 compared to -O2, but generally not the opposite.
 
 In the original example, GCC cannot prove anything about run time, so that
 according to the gcc man page, one should get a warning whatever the
 optimization level.

f(i) is considered as an initialization of i. This heuristic is necessary,
otherwise the number of false positives would make the warning useless.

 I've another example (similar to the MPFR code):
 
 int fn3 (void);
 void fn2 (int *p)
 {
   if (fn3 ())
 *p = 0;
 }
 int fn1 (void)
 {
   int c;
   fn2 (c);
   return c;
 }
 
 GCC doesn't give any may be used uninitialized warning (whether -O2 or -O3
 is used). This is incorrect according to the above rule. BTW, for -O3, this
 is surprising because it is similar to the original example.

A different optimization pass (CCP) seems to notice that the value returned is
either 0 or something uninitialized and thus must be 0. Maybe there is an
opportunity for a warning there (though again we need to make sure it won't
cause too many false positives).

I don't know why you think warnings should be so well defined. They have always
been a heuristic compromise.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread manu at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #10 from Manuel López-Ibáñez manu at gcc dot gnu.org ---
(In reply to Vincent Lefèvre from comment #8)
 Concerning the if it cannot prove the uninitialized paths are not executed
 at run time part, GCC should be able to prove more things with -O3 than
 with -O2, meaning that -Wmaybe-uninitialized warnings could disappear with
 -O3 compared to -O2, but generally not the opposite.

Your assumption is mistaken because you don't seem to realize something that
Jakub has said repeatedly. GCC doesn't warn *on purpose* for very common code
such as

{
int c;
f(c);
return c;
}

if GCC doesn't know what is going on within f(), because that will trigger a
lot of false positives (although it is easy to build testcases where warning
would have been warranted). At -O3, that code may be converted to

{
   int c;
   if (g())
   c = 3
return c;
}

and then, even though g() may never return false, if GCC cannot prove that,
then GCC will warn, because not warning will case a lot of false negatives.
Such design decisions are based on experience.

Now, I agree that ideally, GCC should warn for your last testcase. But I guess
in that case inlining either doesn't happen or it happens too late, so GCC only
sees the first case. The analysis that GCC performs are predicated on the
transformations leading to better code, otherwise they are not performed. A
tool for static analysis will surely inline as much as it could, not matter if
the code is slower or larger, but this is not how GCC works because GCC is not
a tool for static analysis.

On the other hand, GCC has bugs (missed optimizations, PR24639), and it would
be nice if more people worked on those, but this PR doesn't look like one.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread manu at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

Manuel López-Ibáñez manu at gcc dot gnu.org changed:

   What|Removed |Added

 CC||manu at gcc dot gnu.org

--- Comment #11 from Manuel López-Ibáñez manu at gcc dot gnu.org ---
(In reply to Marc Glisse from comment #9)
 A different optimization pass (CCP) seems to notice that the value returned
 is either 0 or something uninitialized and thus must be 0. Maybe there is an
 opportunity for a warning there (though again we need to make sure it won't
 cause too many false positives).

Actually this missed warning is the infamous PR18501.

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread jakub at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #12 from Jakub Jelinek jakub at gcc dot gnu.org ---
Only in your reading of the documentation.

You clearly don't know what you are asking for, even the very common case of
pthread_t th;
if (pthread_create (th, NULL, tf, NULL))
  goto fail;
pthread_join (th, NULL);
case would need to be warned about, even when there is nothing wrong about it.
In your testcase, if fn1 isn't inlined, it is the same thing for GCC, a
function call as a black box which could do anything to the memory pointed to
by the escaped pointer (unless the function is say pure or const, at which
point it couldn't store to it).  If it is inlined, the compiler sees it, sees
that a variable is used and in certain path has uninitialized value and in
others initialized, and correctly warns.


[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread glisse at gcc dot gnu.org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #13 from Marc Glisse glisse at gcc dot gnu.org ---
(In reply to Manuel López-Ibáñez from comment #10)
 Now, I agree that ideally, GCC should warn for your last testcase. But I
 guess in that case inlining either doesn't happen or it happens too late, so
 GCC only sees the first case.

Actually it is the reverse, inlining happens earlier in this new testcase (the
first example was recursive, which makes the inliner more conservative).

 The analysis that GCC performs are predicated
 on the transformations leading to better code, otherwise they are not
 performed. A tool for static analysis will surely inline as much as it
 could, not matter if the code is slower or larger, but this is not how GCC
 works because GCC is not a tool for static analysis.

Maybe we could have a wiki page explaining what options to tweak (inlining
parameters, etc) for a compilation where you are only interested in warnings?
(I had vaguely mentioned creating -Ow at some point, but that didn't seem such
a good idea)

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread vincent-gcc at vinc17 dot net
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #14 from Vincent Lefèvre vincent-gcc at vinc17 dot net ---
(In reply to Marc Glisse from comment #9)
 The definition of a function changes with inlining ;-)

It shouldn't: what happens at run time isn't changed by inlining.

 f(i) is considered as an initialization of i. This heuristic is necessary,
 otherwise the number of false positives would make the warning useless.

Perhaps, but this isn't documented.

 I don't know why you think warnings should be so well defined.

According to the gcc man page, it is well-defined: the rule is given
explicitly.

(In reply to Jakub Jelinek from comment #12)
 In your testcase, if fn1 isn't inlined, it is the same thing for GCC, a
 function call as a black box which could do anything to the memory pointed
 to by the escaped pointer (unless the function is say pure or const, at
 which point it couldn't store to it).

Here you assume that the function can do anything, while Marc said that GCC
assumes that i is initialized. There's a contradiction.

Moreover in the case of MPFR, the called function is in the same preprocessed
source file, so that it is not obvious for the user that GCC will see it as a
black box (when not inlined).

[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2

2014-02-13 Thread vincent-gcc at vinc17 dot net
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165

--- Comment #15 from Vincent Lefèvre vincent-gcc at vinc17 dot net ---
(In reply to Manuel López-Ibáñez from comment #10)
 Now, I agree that ideally, GCC should warn for your last testcase. But I
 guess in that case inlining either doesn't happen or it happens too late, so
 GCC only sees the first case. The analysis that GCC performs are predicated
 on the transformations leading to better code, otherwise they are not
 performed. A tool for static analysis will surely inline as much as it
 could, not matter if the code is slower or larger, but this is not how GCC
 works because GCC is not a tool for static analysis.

Well, detecting uninitialized variables is equivalent to generating better
code. See the following functions. If you want to be able to remove the i == 0
test in the first one (making generated code better), you'll solve the warning
problem in the second one.

int f(void)
{
  int i = 0;
  /* some code that sets i to a nonzero value, but difficult to prove */
  if (i == 0)
abort();
  return i;
}

int f(void)
{
  int i;
  /* some code that sets i to a nonzero value, but difficult to prove */
  return i;
}