Fix -Os related -Werror failures.

Message ID 6eac682f-26fa-6a47-9497-357206266ba1@redhat.com
State Dropped
Headers

Commit Message

Carlos O'Donell Oct. 28, 2016, 4:46 a.m. UTC
  While investigating bug 20729 I decided to fix up the -Wmaybe-uninitialized
errors caused by building with -Os rather than build with -Wno-error.
The comments provide all the details.

No regressions on x86_64 and x86 (building with -O2). There are _tons_
of failures building with -Os, but nothing that is novel, lots of linkspace
failures because of lack of inlining, and lots of extra PLT references that
should not be in the dynamic loader, all things that would need fixing.

Is there value in checking in these fixes then to let others work out the
-Os failures?

2016-10-27  Carlos O'Donell  <carlos@redhat.com>

	* iso-2022-cn-ext.c: Include libc-internal.h and ignore
	-Wmaybe-uninitialized for BODY macro.
	* locale/weight.h (findix): Ignore -Wmaybe-uninitialized error
	for seq2.back_us and seq1.back_us.
	* locale/weightwc.h (findix): Likewise.
	* nptl_db/thread_dbP.h: Ignore -Wmaybe-uninitialized error for
	DB_GET_FIELD_ADDRESS.
	* resolv/res_send (reopen): Ignore -Wmaybe-uninitialized error for
	slen.
	* string/strcoll_l.c (get_next_seq): Ignore -Wmaybe-uninitialized
	for seq2.save_idx and seq1.save_idx.

---
  

Comments

Andreas Schwab Oct. 28, 2016, 6:25 a.m. UTC | #1
On Okt 28 2016, Carlos O'Donell <carlos@redhat.com> wrote:

> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");

That should use 5, we never distinguish different patch releases.

Andreas.
  
Florian Weimer Oct. 28, 2016, 6:32 a.m. UTC | #2
On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
> +   that buf[0] and buf[1] may be used uninitialized.  This can only
> +   happen in the case where tmpbuf[3] is used, and in that case the
> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
> +   is in getting the compiler to see this logic because tmpbuf[0] is
> +   involved in determining the code page and is the indicator that
> +   tmpbuf[2] is initialized.  */
> +DIAG_PUSH_NEEDS_COMMENT;
> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");

This hides the warning for -O2 builds as well, so I don't think this is 
a good idea.

Those who want to build with -Os or other special compiler flags should 
just configure with --disable-werror.  We can't account for every 
optimization someone might want to disable in their build.

Florian
  
Jeff Law Oct. 28, 2016, 6:44 a.m. UTC | #3
On 10/28/2016 12:32 AM, Florian Weimer wrote:
> On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
>> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
>> +   that buf[0] and buf[1] may be used uninitialized.  This can only
>> +   happen in the case where tmpbuf[3] is used, and in that case the
>> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
>> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
>> +   is in getting the compiler to see this logic because tmpbuf[0] is
>> +   involved in determining the code page and is the indicator that
>> +   tmpbuf[2] is initialized.  */
>> +DIAG_PUSH_NEEDS_COMMENT;
>> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
>
> This hides the warning for -O2 builds as well, so I don't think this is
> a good idea.
>
> Those who want to build with -Os or other special compiler flags should
> just configure with --disable-werror.  We can't account for every
> optimization someone might want to disable in their build.
That'd be my recommendation.

What often happens in these cases is the compiler in its default mode of 
operation is able to statically eliminate a conditional branch on a 
particular path.  However, to do so the compiler has to duplicate code.

Not surprisingly, there's a cost/benefit tradeoff here and the 
heuristics are largely driven by the real or estimated profile data as 
well as the coarser "optimize for code space".  So changing flags 
changes the output of those heuristics and ultimately can result in 
leaving paths in the CFG that can not be executed -- and that often 
leads to false positive may-be-uninitialized warnings and such.

Long term I would like to find a good way to mark paths that are not 
executable, but are not profitable to eliminate, then utilize that 
information to prune various "may" warnings.  That would make those kind 
of warnings more stable across different optimization levels as well as 
more stable release-to-release.  But that's definitely in the "future 
work" area.

jeff
  
Arnd Bergmann Oct. 28, 2016, 8:12 a.m. UTC | #4
On Friday, October 28, 2016 12:44:32 AM CEST Jeff Law wrote:
> On 10/28/2016 12:32 AM, Florian Weimer wrote:
> > On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
> >> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
> >> +   that buf[0] and buf[1] may be used uninitialized.  This can only
> >> +   happen in the case where tmpbuf[3] is used, and in that case the
> >> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
> >> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
> >> +   is in getting the compiler to see this logic because tmpbuf[0] is
> >> +   involved in determining the code page and is the indicator that
> >> +   tmpbuf[2] is initialized.  */
> >> +DIAG_PUSH_NEEDS_COMMENT;
> >> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
> >
> > This hides the warning for -O2 builds as well, so I don't think this is
> > a good idea.
> >
> > Those who want to build with -Os or other special compiler flags should
> > just configure with --disable-werror.  We can't account for every
> > optimization someone might want to disable in their build.
> That'd be my recommendation.
> 
> What often happens in these cases is the compiler in its default mode of 
> operation is able to statically eliminate a conditional branch on a 
> particular path.  However, to do so the compiler has to duplicate code.
> 
> Not surprisingly, there's a cost/benefit tradeoff here and the 
> heuristics are largely driven by the real or estimated profile data as 
> well as the coarser "optimize for code space".  So changing flags 
> changes the output of those heuristics and ultimately can result in 
> leaving paths in the CFG that can not be executed -- and that often 
> leads to false positive may-be-uninitialized warnings and such.
> 
> Long term I would like to find a good way to mark paths that are not 
> executable, but are not profitable to eliminate, then utilize that 
> information to prune various "may" warnings.  That would make those kind 
> of warnings more stable across different optimization levels as well as 
> more stable release-to-release.  But that's definitely in the "future 
> work" area.

I've spent a lot of time trying to eliminate -Wmaybe-uninitialized
warnings from the Linux kernel. Here are some data points that you
may find useful too:

- Building with -Os causes many false positives starting with gcc-4.9,
  and I have disabled the warning for this specific flag. I believe
  this is due to the lack of the "-fschedule-insns" optimization step
- Building with -O3 apparently also causes some false positives, but
  we don't normally do that in the kernel, and the only architecture
  port that does it also disables the warnings
- Two more gcc options that cause false positives are -fprofile-arcs
  and some of the -fsanitize=... options
- overall, gcc-4.9 improved much over gcc-4.8 in these warnings,
  but they have a different set of false-positives. As gcc-4.8 is
  getting old, I'm pushing a patch to also disable the warning
  for all 4.8 builds. Prior to v4.8, there was no option to disable
  maybe-uninitialized warnings.
- gcc-5 and gcc-6 appear to be slightly better than gcc-4.9 but also
  introduce a small number of additional false-positive warnings,
  apparently this happens mostly because they make different
  inlining decisions, not because something fundamentally changed.
  Generally speaking, if any of 4.9, 4.x or 5.x produce a warning
  in some configurations, it's likely that the other ones will
  do the same, depending on a combination target architecture and
  optimization flags that impact inlining.
- I found that most often when gcc is confused about whether a
  variable is uninitialized or not, the source code tends to be
  confusing to a human reader as well and rewriting it differently
  results in better readability and better object code while
  avoiding the warning. There are always other cases in which
  this is not possible though.

	Arnd
  
Andrew Pinski Oct. 28, 2016, 8:17 a.m. UTC | #5
On Fri, Oct 28, 2016 at 1:12 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday, October 28, 2016 12:44:32 AM CEST Jeff Law wrote:
>> On 10/28/2016 12:32 AM, Florian Weimer wrote:
>> > On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
>> >> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
>> >> +   that buf[0] and buf[1] may be used uninitialized.  This can only
>> >> +   happen in the case where tmpbuf[3] is used, and in that case the
>> >> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
>> >> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
>> >> +   is in getting the compiler to see this logic because tmpbuf[0] is
>> >> +   involved in determining the code page and is the indicator that
>> >> +   tmpbuf[2] is initialized.  */
>> >> +DIAG_PUSH_NEEDS_COMMENT;
>> >> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
>> >
>> > This hides the warning for -O2 builds as well, so I don't think this is
>> > a good idea.
>> >
>> > Those who want to build with -Os or other special compiler flags should
>> > just configure with --disable-werror.  We can't account for every
>> > optimization someone might want to disable in their build.
>> That'd be my recommendation.
>>
>> What often happens in these cases is the compiler in its default mode of
>> operation is able to statically eliminate a conditional branch on a
>> particular path.  However, to do so the compiler has to duplicate code.
>>
>> Not surprisingly, there's a cost/benefit tradeoff here and the
>> heuristics are largely driven by the real or estimated profile data as
>> well as the coarser "optimize for code space".  So changing flags
>> changes the output of those heuristics and ultimately can result in
>> leaving paths in the CFG that can not be executed -- and that often
>> leads to false positive may-be-uninitialized warnings and such.
>>
>> Long term I would like to find a good way to mark paths that are not
>> executable, but are not profitable to eliminate, then utilize that
>> information to prune various "may" warnings.  That would make those kind
>> of warnings more stable across different optimization levels as well as
>> more stable release-to-release.  But that's definitely in the "future
>> work" area.
>
> I've spent a lot of time trying to eliminate -Wmaybe-uninitialized
> warnings from the Linux kernel. Here are some data points that you
> may find useful too:
>
> - Building with -Os causes many false positives starting with gcc-4.9,
>   and I have disabled the warning for this specific flag. I believe
>   this is due to the lack of the "-fschedule-insns" optimization step

No this is false.  It is usually due to jump threading is not as
aggressive at -O2 than -Os due to -Os not wanting to increase code
size.

Thanks,
Andrew

> - Building with -O3 apparently also causes some false positives, but
>   we don't normally do that in the kernel, and the only architecture
>   port that does it also disables the warnings
> - Two more gcc options that cause false positives are -fprofile-arcs
>   and some of the -fsanitize=... options
> - overall, gcc-4.9 improved much over gcc-4.8 in these warnings,
>   but they have a different set of false-positives. As gcc-4.8 is
>   getting old, I'm pushing a patch to also disable the warning
>   for all 4.8 builds. Prior to v4.8, there was no option to disable
>   maybe-uninitialized warnings.
> - gcc-5 and gcc-6 appear to be slightly better than gcc-4.9 but also
>   introduce a small number of additional false-positive warnings,
>   apparently this happens mostly because they make different
>   inlining decisions, not because something fundamentally changed.
>   Generally speaking, if any of 4.9, 4.x or 5.x produce a warning
>   in some configurations, it's likely that the other ones will
>   do the same, depending on a combination target architecture and
>   optimization flags that impact inlining.
> - I found that most often when gcc is confused about whether a
>   variable is uninitialized or not, the source code tends to be
>   confusing to a human reader as well and rewriting it differently
>   results in better readability and better object code while
>   avoiding the warning. There are always other cases in which
>   this is not possible though.
>
>         Arnd
  
Carlos O'Donell Oct. 28, 2016, 12:08 p.m. UTC | #6
On 10/28/2016 02:32 AM, Florian Weimer wrote:
> On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
>> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
>> +   that buf[0] and buf[1] may be used uninitialized.  This can only
>> +   happen in the case where tmpbuf[3] is used, and in that case the
>> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
>> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
>> +   is in getting the compiler to see this logic because tmpbuf[0] is
>> +   involved in determining the code page and is the indicator that
>> +   tmpbuf[2] is initialized.  */
>> +DIAG_PUSH_NEEDS_COMMENT;
>> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
> 
> This hides the warning for -O2 builds as well, so I don't think this is a good idea.
> 
> Those who want to build with -Os or other special compiler flags
> should just configure with --disable-werror. We can't account for
> every optimization someone might want to disable in their build.

I agree that we can't account for _all_ optimizations someone might want
to disable in their build, but I think it is a reasonable goal to target
a few key _default_ optimization including -O3, -O2, and -Os.

In the case above we only limit the emitted warnings for the narrow
code involved in iso-2022-cn-ext conversions. I'd be more worried if it
required a widely used function with broadly disabled warnings.

I agree with Arnd that this code is _overly_ complex and could be
rewritten such that it's a little clearer and makes sense to the compiler
at -Os.

Should I try to cleanup the BODY code a bit to remove this particular
diagnostic disabling?

I know we've had several real uninitialized variable problems in the
conversion code recently, so I'm also interested in having the compiler
help us find more of these problems.
  
Florian Weimer Oct. 28, 2016, 12:43 p.m. UTC | #7
On 10/28/2016 02:08 PM, Carlos O'Donell wrote:
> On 10/28/2016 02:32 AM, Florian Weimer wrote:
>> On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
>>> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
>>> +   that buf[0] and buf[1] may be used uninitialized.  This can only
>>> +   happen in the case where tmpbuf[3] is used, and in that case the
>>> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
>>> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
>>> +   is in getting the compiler to see this logic because tmpbuf[0] is
>>> +   involved in determining the code page and is the indicator that
>>> +   tmpbuf[2] is initialized.  */
>>> +DIAG_PUSH_NEEDS_COMMENT;
>>> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
>>
>> This hides the warning for -O2 builds as well, so I don't think this is a good idea.
>>
>> Those who want to build with -Os or other special compiler flags
>> should just configure with --disable-werror. We can't account for
>> every optimization someone might want to disable in their build.
>
> I agree that we can't account for _all_ optimizations someone might want
> to disable in their build, but I think it is a reasonable goal to target
> a few key _default_ optimization including -O3, -O2, and -Os.
>
> In the case above we only limit the emitted warnings for the narrow
> code involved in iso-2022-cn-ext conversions. I'd be more worried if it
> required a widely used function with broadly disabled warnings.

We can probably find a compiler flag which needs this for a central 
function.

This might not look like a lot of work now, but it's an ongoing effort, 
for every target, GCC version, and flag variant.  It does not help 
default builds at all (in fact, it has some slight risk interfering with 
future development because we might miss some warning as a result).  I 
think it's just a distraction.

And with -Os in particular, the resulting libc is not really ABI-compliant.

Florian
  
Joseph Myers Oct. 28, 2016, 12:49 p.m. UTC | #8
On Fri, 28 Oct 2016, Florian Weimer wrote:

> Those who want to build with -Os or other special compiler flags should just
> configure with --disable-werror.  We can't account for every optimization
> someone might want to disable in their build.

I don't think --disable-werror should be encouraged.  We could add DIAG_* 
macro variants that do nothing except with -Os so don't disable the 
warnings in other cases, if there isn't a code cleanup to avoid the 
warnings.
  
Florian Weimer Oct. 28, 2016, 12:55 p.m. UTC | #9
On 10/28/2016 02:49 PM, Joseph Myers wrote:
> On Fri, 28 Oct 2016, Florian Weimer wrote:
>
>> Those who want to build with -Os or other special compiler flags should just
>> configure with --disable-werror.  We can't account for every optimization
>> someone might want to disable in their build.
>
> I don't think --disable-werror should be encouraged.

-Wmaybe-uninitialized warnings can be issued very late from the 
optimizers, so this is very much a corner case in terms of usefulness 
for -Werror because it is practically guaranteed to have new false 
positives with unusual architectures, compiler versions, and 
optimization flags.

If the presence of this warning in particular leads people to use 
--disable-werror, maybe we should remove it from the default set of 
warnings which trigger errors.

Florian
  
Joseph Myers Oct. 28, 2016, 1:04 p.m. UTC | #10
On Fri, 28 Oct 2016, Carlos O'Donell wrote:

> I agree that we can't account for _all_ optimizations someone might want
> to disable in their build, but I think it is a reasonable goal to target
> a few key _default_ optimization including -O3, -O2, and -Os.

And -O1 (bug 19444).  And -Og for debuggability.

> I agree with Arnd that this code is _overly_ complex and could be
> rewritten such that it's a little clearer and makes sense to the compiler
> at -Os.

In general, making code clearer is a good approach.

For -O1 / -Og I'd also be willing to consider default initializers as a 
less verbose way than DIAG_* macros of making it obvious to the compiler 
that a variable is initialized (at -Os, that may not be such a good idea 
because presumably the user cares about saving a few instructions from an 
unnecessary initialization).
  
Carlos O'Donell Oct. 28, 2016, 1:18 p.m. UTC | #11
On 10/28/2016 08:55 AM, Florian Weimer wrote:
> On 10/28/2016 02:49 PM, Joseph Myers wrote:
>> On Fri, 28 Oct 2016, Florian Weimer wrote:
>> 
>>> Those who want to build with -Os or other special compiler flags
>>> should just configure with --disable-werror.  We can't account
>>> for every optimization someone might want to disable in their
>>> build.
>> 
>> I don't think --disable-werror should be encouraged.
> 
> -Wmaybe-uninitialized warnings can be issued very late from the
> optimizers, so this is very much a corner case in terms of usefulness
> for -Werror because it is practically guaranteed to have new false
> positives with unusual architectures, compiler versions, and
> optimization flags.
> 
> If the presence of this warning in particular leads people to use
> --disable-werror, maybe we should remove it from the default set of
> warnings which trigger errors.

Remove -Wmaybe-uninitialized?

That destroys some of the value of the warning and means we don't
interact with upstream gcc to make it better, either during initial
review or reviews when the gcc version gets new enough that we audit
the diagnostic.

I would rather follow Joseph's suggestion of adding optimization
specific DIAG_* macros.

e.g.
	DIAG_IGNORE_O3_NEEDS_COMMENT
	DIAG_IGNORE_O2_NEEDS_COMMENT
	DIAG_IGNORE_O1_NEEDS_COMMENT
	DIAG_IGNORE_Os_NEEDS_COMMENT
	DIAG_IGNORE_Og_NEEDS_COMMENT

Where the diagnostic is only ignored for the relevant optimization
mode.

This way the patch I just suggested would use the *_Os_* variants
and not interfere with -O2 builds. Since the kinds of warnings
generated are rather tightly coupled with the optimization passes
that are enabled, it makes sense to specialize them a bit.
  
Jeff Law Oct. 28, 2016, 1:28 p.m. UTC | #12
On 10/28/2016 02:17 AM, Andrew Pinski wrote:
> On Fri, Oct 28, 2016 at 1:12 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> On Friday, October 28, 2016 12:44:32 AM CEST Jeff Law wrote:
>>> On 10/28/2016 12:32 AM, Florian Weimer wrote:
>>>> On 10/28/2016 06:46 AM, Carlos O'Donell wrote:
>>>>> +/* With GCC 5.3 when compiling with -Os the compiler emits a warning
>>>>> +   that buf[0] and buf[1] may be used uninitialized.  This can only
>>>>> +   happen in the case where tmpbuf[3] is used, and in that case the
>>>>> +   write to the tmpbuf[1] and tmpbuf[2] was assured because
>>>>> +   ucs4_to_cns11643 would have filled in those entries.  The difficulty
>>>>> +   is in getting the compiler to see this logic because tmpbuf[0] is
>>>>> +   involved in determining the code page and is the indicator that
>>>>> +   tmpbuf[2] is initialized.  */
>>>>> +DIAG_PUSH_NEEDS_COMMENT;
>>>>> +DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
>>>>
>>>> This hides the warning for -O2 builds as well, so I don't think this is
>>>> a good idea.
>>>>
>>>> Those who want to build with -Os or other special compiler flags should
>>>> just configure with --disable-werror.  We can't account for every
>>>> optimization someone might want to disable in their build.
>>> That'd be my recommendation.
>>>
>>> What often happens in these cases is the compiler in its default mode of
>>> operation is able to statically eliminate a conditional branch on a
>>> particular path.  However, to do so the compiler has to duplicate code.
>>>
>>> Not surprisingly, there's a cost/benefit tradeoff here and the
>>> heuristics are largely driven by the real or estimated profile data as
>>> well as the coarser "optimize for code space".  So changing flags
>>> changes the output of those heuristics and ultimately can result in
>>> leaving paths in the CFG that can not be executed -- and that often
>>> leads to false positive may-be-uninitialized warnings and such.
>>>
>>> Long term I would like to find a good way to mark paths that are not
>>> executable, but are not profitable to eliminate, then utilize that
>>> information to prune various "may" warnings.  That would make those kind
>>> of warnings more stable across different optimization levels as well as
>>> more stable release-to-release.  But that's definitely in the "future
>>> work" area.
>>
>> I've spent a lot of time trying to eliminate -Wmaybe-uninitialized
>> warnings from the Linux kernel. Here are some data points that you
>> may find useful too:
>>
>> - Building with -Os causes many false positives starting with gcc-4.9,
>>   and I have disabled the warning for this specific flag. I believe
>>   this is due to the lack of the "-fschedule-insns" optimization step
>
> No this is false.  It is usually due to jump threading is not as
> aggressive at -O2 than -Os due to -Os not wanting to increase code
> size.
Correct.  The scheduler has nothing to do with this issue, it's 
primarily jump threading.  At -Os we don't allow as much block copying 
which results in many jump threads not being optimized.  The reduced 
jump threading leaves unexecutable paths in the CFG and results in false 
positive -Wuninitialized errors.

PGO can have similar effects as profiling data may indicate that a 
particular path is not worth duplicating to eliminate a conditional

Inlining goes both ways.  By exposing more code to the optimizers, we 
can often do a better job at eliminating false positives.  But it is 
also the case that inlining may remove the addressability property on an 
object which in turn exposes the object to these kinds of analysis.

Similarly for SRA, function splitting, etc etc.
Jeff
  
Paul Eggert Oct. 28, 2016, 8:10 p.m. UTC | #13
On 10/28/2016 01:12 AM, Arnd Bergmann wrote:
> I found that most often when gcc is confused about whether a variable is uninitialized or not, the source code tends to be confusing to a human reader as well and rewriting it differently results in better readability and better object code while avoiding the warning.

I'm afraid my experience has not been so good. Maybe 1/3 of the time rewriting is better, but otherwise rewriting doesn't help or even confuses the code. When that happens with -Wmaybe-uninitialized, in Emacs we typically use C declarations like this:

       ptrdiff_t offset2 UNINIT; /* The UNINIT works around GCC bug 
78081.  */

where UNINIT is defined something like this:

   #ifdef GCC_LINT
   # define UNINIT = {0,}
   #else
   # define UNINIT /* empty */
   #endif

and configuring with --enable-gcc-warnings compiles with something like 
'gcc -Wall -Werror -DGCC_LINT'.
  
Jeff Law Oct. 29, 2016, 3:03 a.m. UTC | #14
On 10/28/2016 02:10 PM, Paul Eggert wrote:
> On 10/28/2016 01:12 AM, Arnd Bergmann wrote:
>> I found that most often when gcc is confused about whether a variable
>> is uninitialized or not, the source code tends to be confusing to a
>> human reader as well and rewriting it differently results in better
>> readability and better object code while avoiding the warning.
>
> I'm afraid my experience has not been so good. Maybe 1/3 of the time
> rewriting is better, but otherwise rewriting doesn't help or even
> confuses the code. When that happens with -Wmaybe-uninitialized, in
> Emacs we typically use C declarations like this:
>
>       ptrdiff_t offset2 UNINIT; /* The UNINIT works around GCC bug
> 78081.  */
And I would echo that markup indicating that the initializer is to work 
around a GCC false positive is something I wish we had strictly enforced 
within GCC itself when it was made Wuninitialized clean.

GCC has made significant strides in its jump threading and predicate 
analysis to significantly such false positives and many of these 
initializers could probably be removed at this point.

>
> where UNINIT is defined something like this:
>
>   #ifdef GCC_LINT
>   # define UNINIT = {0,}
>   #else
>   # define UNINIT /* empty */
>   #endif
>
> and configuring with --enable-gcc-warnings compiles with something like
> 'gcc -Wall -Werror -DGCC_LINT'.\
But I would caution against blindly using 0 as an initializer.  Each 
case has to be examined to determine what a safe value would be.  Often 
0 is appropriate, but there are certainly cases where it is not the safe 
initializer to use.

Jeff
  
Paul Eggert Oct. 30, 2016, 4:25 a.m. UTC | #15
Jeff Law wrote:
> I would caution against blindly using 0 as an initializer.

Yes, in Emacs we use 0 only when the value does not matter so all values are 
equally "safe". It's merely a convenience to use 0, as 0 is valid for pointers 
as well as for numbers so we can use the same macro for both. We're just trying 
to pacify GCC when warnings are enabled when developing; typically in production 
warnings are disabled and there is no initializer at all.
  

Patch

diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c
index df5b5df..6c9fc97 100644
--- a/iconvdata/iso-2022-cn-ext.c
+++ b/iconvdata/iso-2022-cn-ext.c
@@ -27,6 +27,7 @@ 
 #include "cns11643.h"
 #include "cns11643l1.h"
 #include "cns11643l2.h"
+#include <libc-internal.h>
 
 #include <assert.h>
 
@@ -394,6 +395,16 @@  enum
 #define MIN_NEEDED_OUTPUT	TO_LOOP_MIN_NEEDED_TO
 #define MAX_NEEDED_OUTPUT	TO_LOOP_MAX_NEEDED_TO
 #define LOOPFCT			TO_LOOP
+/* With GCC 5.3 when compiling with -Os the compiler emits a warning
+   that buf[0] and buf[1] may be used uninitialized.  This can only
+   happen in the case where tmpbuf[3] is used, and in that case the
+   write to the tmpbuf[1] and tmpbuf[2] was assured because
+   ucs4_to_cns11643 would have filled in those entries.  The difficulty
+   is in getting the compiler to see this logic because tmpbuf[0] is
+   involved in determining the code page and is the indicator that
+   tmpbuf[2] is initialized.  */
+DIAG_PUSH_NEEDS_COMMENT;
+DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
 #define BODY \
   {									      \
     uint32_t ch;							      \
@@ -645,6 +656,7 @@  enum
     /* Now that we wrote the output increment the input pointer.  */	      \
     inptr += 4;								      \
   }
+DIAG_POP_NEEDS_COMMENT;
 #define EXTRA_LOOP_DECLS	, int *setp
 #define INIT_PARAMS		int set = (*setp >> 3) & CURRENT_MASK; \
 				int ann = (*setp >> 3) & ~CURRENT_MASK
diff --git a/locale/weight.h b/locale/weight.h
index c99730c..4c35313 100644
--- a/locale/weight.h
+++ b/locale/weight.h
@@ -61,9 +61,17 @@  findidx (const int32_t *table,
 	     already.  */
 	  size_t cnt;
 
+	  /* With GCC 5.3 when compiling with -Os the compiler warns
+	     that seq2.back_us, which becomes usrc, might be used
+	     uninitialized.  This can't be true because we pass a length
+	     of -1 for len at the same time which means that this loop
+	     never executes.  */
+	  DIAG_PUSH_NEEDS_COMMENT;
+	  DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
 	  for (cnt = 0; cnt < nhere && cnt < len; ++cnt)
 	    if (cp[cnt] != usrc[cnt])
 	      break;
+	  DIAG_POP_NEEDS_COMMENT;
 
 	  if (cnt == nhere)
 	    {
diff --git a/locale/weightwc.h b/locale/weightwc.h
index ab26482..5dcfb2e 100644
--- a/locale/weightwc.h
+++ b/locale/weightwc.h
@@ -59,9 +59,17 @@  findidx (const int32_t *table,
 	     already.  */
 	  size_t cnt;
 
+	  /* With GCC 5.3 when compiling with -Os the compiler warns
+	     that seq2.back_us, which becomes usrc, might be used
+	     uninitialized.  This can't be true because we pass a length
+	     of -1 for len at the same time which means that this loop
+	     never executes.  */
+	  DIAG_PUSH_NEEDS_COMMENT;
+	  DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
 	  for (cnt = 0; cnt < nhere && cnt < len; ++cnt)
 	    if (cp[cnt] != usrc[cnt])
 	      break;
+	  DIAG_POP_NEEDS_COMMENT;
 
 	  if (cnt == nhere)
 	    {
diff --git a/nptl_db/thread_dbP.h b/nptl_db/thread_dbP.h
index 39c3061..116a546 100644
--- a/nptl_db/thread_dbP.h
+++ b/nptl_db/thread_dbP.h
@@ -160,10 +160,19 @@  extern ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *modname,
 		   SYM_##type##_FIELD_##field, \
 		   (psaddr_t) 0 + (idx), (ptr), &(var))
 
+/* With GCC 5.3 when compiling with -Os the compiler emits a warning
+   that slot may be used uninitialized.  This is never the case since
+   the dynamic loader initializes the slotinfo list and
+   dtv_slotinfo_list will point slot at the first entry.  Therefore
+   when DB_GET_FIELD_ADDRESS is called with a slot for ptr, the slot is
+   always initialized.  */
+DIAG_PUSH_NEEDS_COMMENT;
+DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
 #define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx) \
   ((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field, \
 				    SYM_##type##_FIELD_##field, \
 				    (psaddr_t) 0 + (idx), &(var)))
+DIAG_POP_NEEDS_COMMENT;
 
 extern td_err_e _td_locate_field (td_thragent_t *ta,
 				  db_desc_t desc, int descriptor_name,
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 6d46bb2..19a4c1f 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -930,7 +930,16 @@  reopen (res_state statp, int *terrno, int ns)
 		 * error message is received.  We can thus detect
 		 * the absence of a nameserver without timing out.
 		 */
+		/* With GCC 5.3 when compiling with -Os the compiler
+		   emits a warning that slen may be used uninitialized,
+		   but that is never true.  Both slen and
+		   EXT(statp).nssocks[ns] are initialized together or the
+		   function return -1 before control flow reaches the
+		   call to connect with slen.  */
+		DIAG_PUSH_NEEDS_COMMENT;
+		DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
 		if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) {
+		DIAG_POP_NEEDS_COMMENT;
 			Aerror(statp, stderr, "connect(dg)", errno, nsap);
 			__res_iclose(statp, false);
 			return (0);
diff --git a/string/strcoll_l.c b/string/strcoll_l.c
index 4d1e3ab..8e689ba 100644
--- a/string/strcoll_l.c
+++ b/string/strcoll_l.c
@@ -24,6 +24,7 @@ 
 #include <stdint.h>
 #include <string.h>
 #include <sys/param.h>
+#include <libc-internal.h>
 
 #ifndef STRING_TYPE
 # define STRING_TYPE char
@@ -170,7 +171,19 @@  get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets,
 	    }
 	}
 
+      /* With GCC 5.3 when compiling with -Os the compiler complains
+	 that idx, taken from seq->idx (seq1 or seq2 from STRCOLL) may
+	 be used uninitialized.  In general this can't possibly be true
+	 since seq1.idx and seq2.idx are initialized to zero in the
+	 outer function.  Only one case where seq->idx is restored from
+	 seq->save_idx might result in an uninitialized idx value, but
+	 it is guarded by a sequence of checks against backw_stop which
+	 ensures that seq->save_idx was saved to first and contains a
+	 valid value.  */
+      DIAG_PUSH_NEEDS_COMMENT;
+      DIAG_IGNORE_NEEDS_COMMENT (5.3, "-Wmaybe-uninitialized");
       len = weights[idx++];
+      DIAG_POP_NEEDS_COMMENT;
       /* Skip over indices of previous levels.  */
       for (int i = 0; i < pass; i++)
 	{