diff mbox

Fix warning breaking profiled bootstrap

Message ID 20160807034147.24890-1-andi@firstfloor.org
State New
Headers show

Commit Message

Andi Kleen Aug. 7, 2016, 3:41 a.m. UTC
From: Andi Kleen <ak@linux.intel.com>

This patch fixes an bootstrap error with autoprofiledbootstrap
due to uninitiliazed variables, because the compiler cannot
figure out they don't need to be initialized in an error path.
Just always initialize them.

gcc/:

2016-08-06  Andi Kleen  <ak@linux.intel.com>

	* tree-vrp.c (get_single_symbol): Always initialize inv and neg.
---
 gcc/tree-vrp.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Jeff Law Aug. 8, 2016, 4:53 p.m. UTC | #1
On 08/06/2016 09:41 PM, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
>
> This patch fixes an bootstrap error with autoprofiledbootstrap
> due to uninitiliazed variables, because the compiler cannot
> figure out they don't need to be initialized in an error path.
> Just always initialize them.
>
> gcc/:
>
> 2016-08-06  Andi Kleen  <ak@linux.intel.com>
>
> 	* tree-vrp.c (get_single_symbol): Always initialize inv and neg.
The patch is likely OK, but it'd be useful to know more about precisely 
the use that is causing problems.

Ideally we'd have a test that we could more deeply analyze for paths 
through the CFG that can't be executed.  Finding those paths usually 
both fixes the warning *and* results in better code.  Even if we can't 
fix it now, we can file it away for future work

jeff
Andi Kleen Aug. 9, 2016, 2:43 a.m. UTC | #2
> Ideally we'd have a test that we could more deeply analyze for paths
> through the CFG that can't be executed.  Finding those paths usually
> both fixes the warning *and* results in better code.  Even if we
> can't fix it now, we can file it away for future work

It's multiple variables who are depending on each other, with complex
control flow inbetween. It's not surprising that it loses control
of all the combinations.

You can take a look yourself here:

/home/andi/gcc/git/gcc/gcc/tree-vrp.c: In function 'int compare_values_warnv(tree, tree, bool*)':
/home/andi/gcc/git/gcc/gcc/tree-vrp.c:1251:12: error: 'inv2' may be used uninitialized in this function [-Werror=maybe-uninitialized]
       tree inv = cst1 ? inv2 : inv1;
            ^~~
/home/andi/gcc/git/gcc/gcc/tree-vrp.c:1222:4: error: 'inv1' may be used uninitialized in this function [-Werror=maybe-uninitialized]
       if (strict_overflow_p != NULL
           ~~~~~~~~~~~~~~~~~~~~~~~~~
    && (!inv1 || !TREE_NO_WARNING (val1))
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-Andi
Jeff Law Aug. 11, 2016, 10:28 p.m. UTC | #3
On 08/08/2016 08:43 PM, Andi Kleen wrote:
>> Ideally we'd have a test that we could more deeply analyze for paths
>> through the CFG that can't be executed.  Finding those paths usually
>> both fixes the warning *and* results in better code.  Even if we
>> can't fix it now, we can file it away for future work
>
> It's multiple variables who are depending on each other, with complex
> control flow inbetween. It's not surprising that it loses control
> of all the combinations.
>
> You can take a look yourself here:
>
> /home/andi/gcc/git/gcc/gcc/tree-vrp.c: In function 'int compare_values_warnv(tree, tree, bool*)':
> /home/andi/gcc/git/gcc/gcc/tree-vrp.c:1251:12: error: 'inv2' may be used uninitialized in this function [-Werror=maybe-uninitialized]
>        tree inv = cst1 ? inv2 : inv1;
>             ^~~
> /home/andi/gcc/git/gcc/gcc/tree-vrp.c:1222:4: error: 'inv1' may be used uninitialized in this function [-Werror=maybe-uninitialized]
>        if (strict_overflow_p != NULL
>            ~~~~~~~~~~~~~~~~~~~~~~~~~
>     && (!inv1 || !TREE_NO_WARNING (val1))
>     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 From my reading it looks to me like we could use inv2 uninitialized.

   tree sym1 = get_single_symbol (val1, &neg1, &inv1);
   tree sym2 = get_single_symbol (val2, &neg2, &inv2);


If sym1 results in a return value that is some useful tree and inv1 is 
true and cst1 is true via this call:

   const bool cst1 = is_gimple_min_invariant (val1);


We then need sym2 to result in a return value from get_single_symbol to 
be NULL, but cst2 still be true via this statement:

   const bool cst2 = is_gimple_min_invariant (val2);

If all those conditions can hold, then we'll use inv2 without 
initializing it AFAICT.

The key here is can there be a value for val2 where val2 is an invariant 
not built from PLUS_EXPR, POINTER_PLUS_EXPR, MINUS_EXPR or NEGATE_EXPR. 
I think we can make that happen if val2 is an ADDR_EXPR with an 
invariant address.

So it actually seems to me that unless ADDR_EXPR filtered out elsewhere 
that we've got a real bug here rather than a false positive.  There may 
be others, that's just the first one that stood out.

Or did I miss something?

jeff
Andi Kleen Aug. 12, 2016, 3:28 a.m. UTC | #4
> 
> If sym1 results in a return value that is some useful tree and inv1
> is true and cst1 is true via this call:

The only way for get_single_symbol to return a non NULL tree
is to hit the return at the end -- and that always initializes
inv and neg.

And when the return is NULL the && prevents evaluating 
inv or neg.

So I still think it's a false positive.

-Andi
Jeff Law Aug. 18, 2016, 4:28 p.m. UTC | #5
On 08/11/2016 09:28 PM, Andi Kleen wrote:
>>
>> If sym1 results in a return value that is some useful tree and inv1
>> is true and cst1 is true via this call:
>
> The only way for get_single_symbol to return a non NULL tree
> is to hit the return at the end -- and that always initializes
> inv and neg.
Right.

>
> And when the return is NULL the && prevents evaluating
> inv or neg.
Consider the case where sym1 results in a non-null return value (and 
initializes neg1/inv1), but sym2 results in a null return value, leaving 
neg2/inv2 undefined, but cst2 is can still be true (ADDR_EXPR with an 
invariant address comes to mind).

Thus we can get into these statements:


       tree cst = cst1 ? val1 : val2;
       tree inv = cst1 ? inv2 : inv1;


Note carefully how they test cst1 and depending on its value, they may 
read val2 or inv2.

Jeff
Eric Botcazou Aug. 21, 2016, 8:30 p.m. UTC | #6
> Consider the case where sym1 results in a non-null return value (and
> initializes neg1/inv1), but sym2 results in a null return value, leaving
> neg2/inv2 undefined, but cst2 is can still be true (ADDR_EXPR with an
> invariant address comes to mind).
> 
> Thus we can get into these statements:
> 
> 
>        tree cst = cst1 ? val1 : val2;
>        tree inv = cst1 ? inv2 : inv1;
> 
> 
> Note carefully how they test cst1 and depending on its value, they may
> read val2 or inv2.

The key here is that cst1 cannot be true if sym1 is non-null, same for cst2 
and sym2.

The code is guarded with:

  /* If one is of the form '[-]NAME + CST' and the other is constant, then
     it might be possible to say something depending on the constants.  */
  if ((sym1 && inv1 && cst2) || (sym2 && inv2 && cst1))

If this is the first case, then cst1 is false and val2 and inv1 are read.
If this is the second case, then cst1 is true and val1 and inv2 are read.

So inv2 is read only in the second case, and is initialized.
Jeff Law Sept. 16, 2016, 4:44 p.m. UTC | #7
On 08/21/2016 02:30 PM, Eric Botcazou wrote:
>> Consider the case where sym1 results in a non-null return value (and
>> initializes neg1/inv1), but sym2 results in a null return value, leaving
>> neg2/inv2 undefined, but cst2 is can still be true (ADDR_EXPR with an
>> invariant address comes to mind).
>>
>> Thus we can get into these statements:
>>
>>
>>        tree cst = cst1 ? val1 : val2;
>>        tree inv = cst1 ? inv2 : inv1;
>>
>>
>> Note carefully how they test cst1 and depending on its value, they may
>> read val2 or inv2.
>
> The key here is that cst1 cannot be true if sym1 is non-null, same for cst2
> and sym2.
>
> The code is guarded with:
>
>   /* If one is of the form '[-]NAME + CST' and the other is constant, then
>      it might be possible to say something depending on the constants.  */
>   if ((sym1 && inv1 && cst2) || (sym2 && inv2 && cst1))
>
> If this is the first case, then cst1 is false and val2 and inv1 are read.
> If this is the second case, then cst1 is true and val1 and inv2 are read.
>
> So inv2 is read only in the second case, and is initialized.
THanks.  Sometimes this stuff gets painful to follow :(

It looks like Andi already checked in this change.  Andi, please don't 
do that.  THe patch wasn't approved at the time of your commit and 
there's no indication the change was regression tested.

Jeff
Andi Kleen Sept. 16, 2016, 8:37 p.m. UTC | #8
On Fri, Sep 16, 2016 at 10:44:34AM -0600, Jeff Law wrote:
> On 08/21/2016 02:30 PM, Eric Botcazou wrote:
> > > Consider the case where sym1 results in a non-null return value (and
> > > initializes neg1/inv1), but sym2 results in a null return value, leaving
> > > neg2/inv2 undefined, but cst2 is can still be true (ADDR_EXPR with an
> > > invariant address comes to mind).
> > > 
> > > Thus we can get into these statements:
> > > 
> > > 
> > >        tree cst = cst1 ? val1 : val2;
> > >        tree inv = cst1 ? inv2 : inv1;
> > > 
> > > 
> > > Note carefully how they test cst1 and depending on its value, they may
> > > read val2 or inv2.
> > 
> > The key here is that cst1 cannot be true if sym1 is non-null, same for cst2
> > and sym2.
> > 
> > The code is guarded with:
> > 
> >   /* If one is of the form '[-]NAME + CST' and the other is constant, then
> >      it might be possible to say something depending on the constants.  */
> >   if ((sym1 && inv1 && cst2) || (sym2 && inv2 && cst1))
> > 
> > If this is the first case, then cst1 is false and val2 and inv1 are read.
> > If this is the second case, then cst1 is true and val1 and inv2 are read.
> > 
> > So inv2 is read only in the second case, and is initialized.
> THanks.  Sometimes this stuff gets painful to follow :(
> 
> It looks like Andi already checked in this change.  Andi, please don't do
> that.  THe patch wasn't approved at the time of your commit and there's no
> indication the change was regression tested.

I don't post any patches that are not regression tested.
In fact the patch was needed to run proper regression tests with
profiling on because it was a bootstrap fix.

I had interpreted your earlier comments as approval, and imho
the patch is obvious anyways.

Also I would like to point out that such a long turn around time for
bootstrap fixes (and only out of secondary considerations which had
nothing to do with the actual bootstrap problem) is extremely disruptive for
anyone who actually relies on working bootstraps.

If there's no intention to keep --enable-werror working for all build
options the default should probably change to --disable-werror.

-Andi
diff mbox

Patch

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 44dfc84..7f71f8a 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -893,6 +893,9 @@  get_single_symbol (tree t, bool *neg, tree *inv)
   bool neg_;
   tree inv_;
 
+  *inv = NULL_TREE;
+  *neg = false;
+
   if (TREE_CODE (t) == PLUS_EXPR
       || TREE_CODE (t) == POINTER_PLUS_EXPR
       || TREE_CODE (t) == MINUS_EXPR)