On 2/2/19 1:20 PM, Segher Boessenkool wrote:
> On Fri, Feb 01, 2019 at 12:27:57PM -0700, Jeff Law wrote:
>> On 2/1/19 7:01 AM, Marek Polacek wrote:
>>> On Fri, Feb 01, 2019 at 07:19:25AM -0600, Segher Boessenkool wrote:
>>>> On Fri, Feb 01, 2019 at 12:32:45PM +0100, Marc Glisse wrote:
>>>>> My opinion is that -Wmaybe-uninitialized would serve its purpose better 
>>>>> as 
>>>>> part of -Wextra.
>>>>
>>>> +1
>>>
>>> +1 from me too.
>> I disagree strongly.  If we move it to Wextra it's going to see a lot
>> less usage in real world codebases and potentially lead to the
>> re-introduction of a class of bugs that we've largely helped stomp out.
> 
> The usual workaround, especially for programs that build with multiple
> (i.e. older) versions of GCC, is to initialise any such variable (to an
> either or not useful value) early.  This doesn't fix the actual problem
> usually (which is that your control flow is too complex).
> 
>> It's also the case that maybe uninitialized vs is uninitialized is
>> really just a function of CFG shape.  Give me any "maybe uninitialized"
>> case and I can turn it into a "is uninitialized" with simple block
>> duplication of the forms done by jump threading, path isolation,
>> superblock formation, etc.
> 
> Are you saying that -Wmaybe-uninitialized should be included in
> -Wuninitialized, since it has no extra false positives?  That wasn't true
> at all historically: -Wuninitialized has false positives on paths that
> cannot be executed because of function preconditions, but
> -Wmaybe-uninitialized used to warn for things that can be locally proven to
> never execute, like
>   if (a)
>     b = 42;
>   ...
>   if (a)
>     f(b);
No, I'm saying the distinction between maybe and always uninitialized is
a false distinction.  Code duplication can easily take something that
triggers a "maybe" warning and turn it into a "always" warning.  The
distinction between them is just bogus.



To take your example

if (a)
  b = 42
...
if (a)
  f(b);

Can be rewritten as

if (a) {
  b = 42
  [ copy of ...]
  f (b);
} else {
  ...
  f (b);
}

But more importantly consider when the value flows by way of a PHI
argument.  We consider those "maybe" warnings (and it's not just the
uninitialized warning analysis).  But fairly simple code duplication can
eliminate the flow via PHI and suddenly we go from a "maybe" to an
"always" warning.

Let's consider this...


x4 = PHI (x0(D), x1, x2, x3)
use x4;

That's a maybe uninitialized warning by way of the value flow of x0
through the PHI into x4.

But we can duplicate the block creating something like this:

BB:
x5 = PHI (x0(D))
use x5
goto join

BB:
x4 = PHI (x1, x2, x3)
use x4
goto join


Which we then simplify into

BB:
use x0(D)
goto join

BB:
x4 = PHI (x1, x2, x3)
use x4
goto join


That changes the warning from a maybe-uninitialized into an always
uninitialized.  Note that we still may or may not reach the use at
runtime.   THe distinction between maybe and always is just bogus.

Jeff

Reply via email to