public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Question about -Wstrict-overflow=2
@ 2021-03-06 10:37 Alexander Motzkau
  2021-03-06 11:23 ` Andrew Haley
  0 siblings, 1 reply; 11+ messages in thread
From: Alexander Motzkau @ 2021-03-06 10:37 UTC (permalink / raw)
  To: gcc-help

Hi everyone,

I have a question how to fix a -Wstrict-overflow=2 warning. Please consider
this (very) simplified example:

    #include <stdbool.h>
    #include <stddef.h>

    char* get_buf();
    bool do_round();

    bool fun()
    {
        char *expbuf = get_buf();
        char *argptr = expbuf;
        char *endbuf = expbuf + 120;

        while(true)
        {
            if (argptr >= endbuf)
                return false;

            if (!do_round())
                break;

            argptr++;
        }

        return true;
    }

gcc -O2 -Wstrict-overflow=2 gives a warning 'assuming pointer wraparound
does not occur when comparing P +- C1 with P +- C2 [-Wstrict-overflow]' for
the first if condition in GCC 9 as well as GCC 10. Although the wording of
the warning is questionable - the compiler may always assume I write
standard conforming code without telling me about it - the documentation
says this warning comes when a comparison is simplified to a constant.
A constant result would mean that the if block always or never happens
which would be quite undesirable.

Looking at the assembly output with Matt Godbolt's Compiler Explorer however
it seems that there's nothing wrong. GCC modified the loop to use an index
variable counting from 120 backwards. Clever, but clearly not a constant to
warn about.

So the question is what this warning is really about and how to get rid of
it?

If I change the condition to 'argptr - endbuf >= 0' the warning goes away,
but so does the optimization. The resulting code then has a worse
performance and worse readability.

Is there indeed something wrong with the code that I didn't see?
Or is there anything I can do to silence the warning apart from going to
-Wstrict-overflow=1?

Thanks,
Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-06 10:37 Question about -Wstrict-overflow=2 Alexander Motzkau
@ 2021-03-06 11:23 ` Andrew Haley
  2021-03-06 12:03   ` Alexander Motzkau
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Haley @ 2021-03-06 11:23 UTC (permalink / raw)
  To: gcc-help

On 3/6/21 10:37 AM, Alexander Motzkau via Gcc-help wrote:
> So the question is what this warning is really about and how to get rid of
> it?

The compiler is telling you that it's assuming that expbuf + 120
does not wrap around. There's nothing really mysterious about it.

-- 
Andrew Haley  (he/him)
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
https://keybase.io/andrewhaley
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-06 11:23 ` Andrew Haley
@ 2021-03-06 12:03   ` Alexander Motzkau
  2021-03-07 11:37     ` Andrew Haley
  0 siblings, 1 reply; 11+ messages in thread
From: Alexander Motzkau @ 2021-03-06 12:03 UTC (permalink / raw)
  To: gcc-help

Andrew Haley wrote:
> The compiler is telling you that it's assuming that expbuf + 120
> does not wrap around. There's nothing really mysterious about it.

But should that warning only occur on -Wstrict-overflow=3 or higher?
Why does it occur on -Wstrict-overflow=2?

I usually compile my software with -Werror (so that warnings won't be
ignored anymore) and so this information from the compiler broke the build
when going from GCC 8 to GCC 9. It seems -Wstrict-overflow=2 there is not
fit to be used with -Werror anymore. Am I correct?

Best regards,
Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-06 12:03   ` Alexander Motzkau
@ 2021-03-07 11:37     ` Andrew Haley
  2021-03-07 14:04       ` Alexander Motzkau
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Haley @ 2021-03-07 11:37 UTC (permalink / raw)
  To: gcc-help

On 3/6/21 12:03 PM, Alexander Motzkau via Gcc-help wrote:
> Andrew Haley wrote:
>> The compiler is telling you that it's assuming that expbuf + 120
>> does not wrap around. There's nothing really mysterious about it.
> 
> But should that warning only occur on -Wstrict-overflow=3 or higher?
> Why does it occur on -Wstrict-overflow=2?

-Wstrict-overflow=2 triggers when GCC encounters expressions that
reduce to a constant, where that evaluation depends on overflow not
occuring. In this case the expression is

   expbuf + 120 > get_buf()

This exact phrase doesn't occur in your program, but GCC generates it
while optimizing.

> I usually compile my software with -Werror (so that warnings won't be
> ignored anymore) and so this information from the compiler broke the build
> when going from GCC 8 to GCC 9. It seems -Wstrict-overflow=2 there is not
> fit to be used with -Werror anymore. Am I correct?

I doubt that it ever was. -Wstrict-overflow=2 is informative, for the
programmer. It doesn't suggest that anything is questionable  about the
program, and in this case it's difficult or impossible to avoid.

Re upgrading: over time, GCC gets better and better at diagnosing and
providing information. This inevitably means that programmers using
-Werror with high levels of warnings have to change their programs
when a new GCC is used.

-- 
Andrew Haley  (he/him)
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
https://keybase.io/andrewhaley
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-07 11:37     ` Andrew Haley
@ 2021-03-07 14:04       ` Alexander Motzkau
  2021-03-07 14:56         ` Andrew Haley
                           ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Alexander Motzkau @ 2021-03-07 14:04 UTC (permalink / raw)
  To: gcc-help

Andrew Haley wrote:
> -Wstrict-overflow=2 triggers when GCC encounters expressions that
> reduce to a constant, where that evaluation depends on overflow not
> occuring. In this case the expression is
>
>   expbuf + 120 > get_buf()

If this is the case I can see the merit of the warning, because that can be
reduced to 120 > 0, which is a constant. But my problem ist, that I don't
see where this expression comes from? The condition in question is

    argptr >= endbuf

which can be written as

    expbuf + i >= expbuf + 120

which can be reduced to

    i >= 120

which is not a constant, and therefore not a cause for this warning.

This could get constant if gcc does some loop unrolling, for the first loop
this would result in the expression you quoted. But then I would have hoped
that gcc doesn't warn about constants or dead code when unrolling a loop,
because they naturally happen then. And I can't do anything against it
except unrolling manually and this would make it less readable.

> I doubt that it ever was. -Wstrict-overflow=2 is informative, for the
> programmer. It doesn't suggest that anything is questionable  about the
> program, and in this case it's difficult or impossible to avoid.

If an originally non-constant if-expression is reduced to a constant one
that is for me something to worry about, where a warning/error is
appropriate. It means that the following block is always or never executed,
something the programmer usually didn't intend, otherwise he wouldn't have
written the if-condition.

And this reduction to a constant is what differentiates -Wstrict-overflow=2
from -Wstrict-overflow=3 (according to gcc's documentation). For the later
I would accept your description as it being purely informative.

> Re upgrading: over time, GCC gets better and better at diagnosing and
> providing information. This inevitably means that programmers using
> -Werror with high levels of warnings have to change their programs
> when a new GCC is used.

I understand and I welcome better analysis and optimization techniques.
And I changed several parts due to new warnings. But in this case I don't
see any possibility that wouldn't make the code worse except deactivating
the warning. Which is sad and normally beside the point of a warning.

Thank you for your patience and best regards,
Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-07 14:04       ` Alexander Motzkau
@ 2021-03-07 14:56         ` Andrew Haley
  2021-03-08 16:43           ` Segher Boessenkool
  2021-03-07 15:31         ` Ian Lance Taylor
  2021-03-08 21:05         ` Martin Sebor
  2 siblings, 1 reply; 11+ messages in thread
From: Andrew Haley @ 2021-03-07 14:56 UTC (permalink / raw)
  To: gcc-help

On 3/7/21 2:04 PM, Alexander Motzkau via Gcc-help wrote:
> Andrew Haley wrote:
>> -Wstrict-overflow=2 triggers when GCC encounters expressions that
>> reduce to a constant, where that evaluation depends on overflow not
>> occuring. In this case the expression is
>>
>>   expbuf + 120 > get_buf()
>
> If this is the case

It is. I've looked.

> I can see the merit of the warning, because that can be reduced to
> 120 > 0, which is a constant. But my problem ist, that I don't see
> where this expression comes from?

Surely you can imagine some kinds of loop transformation that might
result in such an expression.

-fdump-tree-all might help you. It won't tell you everything, because
sometimes expressions are generated during an optimization pass and
deleted before the dump. But it might help you to understand the kinds
of transformation that GCC does.

> The condition in question is
>
>     argptr >= endbuf
>
> which can be written as
>
>     expbuf + i >= expbuf + 120
>
> which can be reduced to
>
>     i >= 120
>
> which is not a constant, and therefore not a cause for this warning.
>
> This could get constant if gcc does some loop unrolling, for the
> first loop this would result in the expression you quoted. But then
> I would have hoped that gcc doesn't warn about constants or dead
> code when unrolling a loop, because they naturally happen then.

GCC warns when it encounters such an expression when optimizing.
GCC does not distinguish between user-written expressions and
internally-generated ones.

> And I can't do anything against it except unrolling manually and
> this would make it less readable.

That's right, you can't.

>> I doubt that it ever was. -Wstrict-overflow=2 is informative, for
>> the programmer. It doesn't suggest that anything is questionable
>> about the program, and in this case it's difficult or impossible to
>> avoid.
>
> If an originally non-constant if-expression is reduced to a constant
> one that is for me something to worry about, where a warning/error
> is appropriate. It means that the following block is always or never
> executed, something the programmer usually didn't intend, otherwise
> he wouldn't have written the if-condition.
>
> And this reduction to a constant is what differentiates
> -Wstrict-overflow=2 from -Wstrict-overflow=3 (according to gcc's
> documentation). For the later I would accept your description as it
> being purely informative.

Sure, but I'm telling you what is.

>> Re upgrading: over time, GCC gets better and better at diagnosing and
>> providing information. This inevitably means that programmers using
>> -Werror with high levels of warnings have to change their programs
>> when a new GCC is used.
>
> I understand and I welcome better analysis and optimization
> techniques.  And I changed several parts due to new warnings. But in
> this case I don't see any possibility that wouldn't make the code
> worse except deactivating the warning. Which is sad and normally
> beside the point of a warning.

Not all warnings indicate things that should be changed. We expect
higher levels of warnings to cause false positives, many of which
can't be avoided, which is why such warnings are not included in
-Wall.

-- 
Andrew Haley  (he/him)
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
https://keybase.io/andrewhaley
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-07 14:04       ` Alexander Motzkau
  2021-03-07 14:56         ` Andrew Haley
@ 2021-03-07 15:31         ` Ian Lance Taylor
  2021-03-08 21:05         ` Martin Sebor
  2 siblings, 0 replies; 11+ messages in thread
From: Ian Lance Taylor @ 2021-03-07 15:31 UTC (permalink / raw)
  To: Alexander Motzkau; +Cc: gcc-help

On Sun, Mar 7, 2021, 6:05 AM Alexander Motzkau via Gcc-help <
gcc-help@gcc.gnu.org> wrote:

> Andrew Haley wrote:
> > -Wstrict-overflow=2 triggers when GCC encounters expressions that
> > reduce to a constant, where that evaluation depends on overflow not
> > occuring. In this case the expression is
> >
> >   expbuf + 120 > get_buf()
>
> If this is the case I can see the merit of the warning, because that can be
> reduced to 120 > 0, which is a constant. But my problem ist, that I don't
> see where this expression comes from? The condition in question is
>
>     argptr >= endbuf
>
> which can be written as
>
>     expbuf + i >= expbuf + 120
>
> which can be reduced to
>
>     i >= 120
>
> which is not a constant, and therefore not a cause for this warning.
>

As you said earlier, GCC turns the loop into one with exactly 120
iterations.  That optimization assumes that expbuf + 120 does not overflow;
if it did overflow the loop would not execute exactly 120 times.  That is
why you are getting the warning.  It's not an error; it's GCC informing you
that it is making as optimization decision based on the assumption that
overflow does not occur.

Ian

>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-07 14:56         ` Andrew Haley
@ 2021-03-08 16:43           ` Segher Boessenkool
  0 siblings, 0 replies; 11+ messages in thread
From: Segher Boessenkool @ 2021-03-08 16:43 UTC (permalink / raw)
  To: Andrew Haley; +Cc: gcc-help

On Sun, Mar 07, 2021 at 02:56:27PM +0000, Andrew Haley via Gcc-help wrote:
> On 3/7/21 2:04 PM, Alexander Motzkau via Gcc-help wrote:
> > Andrew Haley wrote:
> >> Re upgrading: over time, GCC gets better and better at diagnosing and
> >> providing information. This inevitably means that programmers using
> >> -Werror with high levels of warnings have to change their programs
> >> when a new GCC is used.
> >
> > I understand and I welcome better analysis and optimization
> > techniques.  And I changed several parts due to new warnings. But in
> > this case I don't see any possibility that wouldn't make the code
> > worse except deactivating the warning. Which is sad and normally
> > beside the point of a warning.
> 
> Not all warnings indicate things that should be changed. We expect
> higher levels of warnings to cause false positives, many of which
> can't be avoided, which is why such warnings are not included in
> -Wall.

Yes.  If GCC would know something it warns about is an error, it should
report it as an error.  But it doesn't know.

Some warnings are for things that GCC knows (or its developers know,
really) are often wrong.  Other warnings are for things that aren't so
often wrong, but have a high impact.  And some are for problems that are
hard to find.

-Werror ignores all of this, and makes every warning an error.  That can
be handy for people who know they will ignore all warnings otherwise,
and it is not a huge deal for warnings that are part of -Wall (because
one of the conditions for being included there is that the problem is
easy to avoid, with a trivial code change).  But -Werror is only for
people who think life is too boring and they need some extra challenges,
otherwise.

There is no reason to avoid all warnings.  It is easy to avoid all -Wall
warnings, or even -Wall -Wextra (although if you never used that before
it will find a *lot* of questionable constructs in your code), but most
other warnings are not in either of those two categories precisely
because they are *not* easy to avoid.


Segher

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-07 14:04       ` Alexander Motzkau
  2021-03-07 14:56         ` Andrew Haley
  2021-03-07 15:31         ` Ian Lance Taylor
@ 2021-03-08 21:05         ` Martin Sebor
  2021-03-08 21:57           ` Alexander Motzkau
  2021-03-09  9:09           ` Andrew Haley
  2 siblings, 2 replies; 11+ messages in thread
From: Martin Sebor @ 2021-03-08 21:05 UTC (permalink / raw)
  To: Alexander Motzkau, gcc-help

On 3/7/21 7:04 AM, Alexander Motzkau via Gcc-help wrote:
> Andrew Haley wrote:
>> -Wstrict-overflow=2 triggers when GCC encounters expressions that
>> reduce to a constant, where that evaluation depends on overflow not
>> occuring. In this case the expression is
>>
>>    expbuf + 120 > get_buf()
> 
> If this is the case I can see the merit of the warning, because that can be
> reduced to 120 > 0, which is a constant. But my problem ist, that I don't
> see where this expression comes from? The condition in question is
> 
>      argptr >= endbuf
> 
> which can be written as
> 
>      expbuf + i >= expbuf + 120
> 
> which can be reduced to
> 
>      i >= 120
> 
> which is not a constant, and therefore not a cause for this warning.
> 
> This could get constant if gcc does some loop unrolling, for the first loop
> this would result in the expression you quoted. But then I would have hoped
> that gcc doesn't warn about constants or dead code when unrolling a loop,
> because they naturally happen then. And I can't do anything against it
> except unrolling manually and this would make it less readable.
> 
>> I doubt that it ever was. -Wstrict-overflow=2 is informative, for the
>> programmer. It doesn't suggest that anything is questionable  about the
>> program, and in this case it's difficult or impossible to avoid.
> 
> If an originally non-constant if-expression is reduced to a constant one
> that is for me something to worry about, where a warning/error is
> appropriate. It means that the following block is always or never executed,
> something the programmer usually didn't intend, otherwise he wouldn't have
> written the if-condition.
> 
> And this reduction to a constant is what differentiates -Wstrict-overflow=2
> from -Wstrict-overflow=3 (according to gcc's documentation). For the later
> I would accept your description as it being purely informative.
> 
>> Re upgrading: over time, GCC gets better and better at diagnosing and
>> providing information. This inevitably means that programmers using
>> -Werror with high levels of warnings have to change their programs
>> when a new GCC is used.
> 
> I understand and I welcome better analysis and optimization techniques.
> And I changed several parts due to new warnings. But in this case I don't
> see any possibility that wouldn't make the code worse except deactivating
> the warning. Which is sad and normally beside the point of a warning.

In the case of flow-dependent warnings there often is a way to rewrite
the code in a way that make it either faster (because it helps GCC see
invariants it can't infer otherwise) or more readable.

I think rewriting the test as an equality would be an improvement:
argptr is incremented by 1 in each iteration so there's no way for
the pointer to be greater than endbuf.

            if (argptr == endbuf)
                 return false;

This avoids the warning and has no change on the emitted code.
(Of course, if the step can be greater than 1 then using equality
wouldn't be appropriate.)

Martin

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-08 21:05         ` Martin Sebor
@ 2021-03-08 21:57           ` Alexander Motzkau
  2021-03-09  9:09           ` Andrew Haley
  1 sibling, 0 replies; 11+ messages in thread
From: Alexander Motzkau @ 2021-03-08 21:57 UTC (permalink / raw)
  To: gcc-help

Martin Sebor wrote:
> I think rewriting the test as an equality would be an improvement:
> argptr is incremented by 1 in each iteration so there's no way for
> the pointer to be greater than endbuf.

The example I gave was very simplified. The original function is much more
complex and argptr is advanced by more than 1 in some cases.

But thank you all for your replies. I understand now, where this warning
comes from (I didn't know -fdump-tree-all, that was very interesting):
GCC does loop header duplication, so the condition is duplicated for the
first iteration and that can (and should) be reduced to a constant assuming
pointers don't wrap around (which they shouldn't).

For now I have turned the comparison of pointers into a comparison of
offsets (by subtraction) to silence the warning. But if GCC gets cleverer
I might remove -Wstrict-overflow=2 alltogether.

Thank you very much
Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Question about -Wstrict-overflow=2
  2021-03-08 21:05         ` Martin Sebor
  2021-03-08 21:57           ` Alexander Motzkau
@ 2021-03-09  9:09           ` Andrew Haley
  1 sibling, 0 replies; 11+ messages in thread
From: Andrew Haley @ 2021-03-09  9:09 UTC (permalink / raw)
  To: gcc-help

On 3/8/21 9:05 PM, Martin Sebor via Gcc-help wrote:
> I think rewriting the test as an equality would be an improvement:
> argptr is incremented by 1 in each iteration so there's no way for
> the pointer to be greater than endbuf.
> 
>             if (argptr == endbuf)
>                  return false;

You can, but it arguably makes the code more fragile and less easy
to reason about. I'm not in favour of tying programs in knots in order
to appease warnings.

-- 
Andrew Haley  (he/him)
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
https://keybase.io/andrewhaley
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-03-09  9:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-06 10:37 Question about -Wstrict-overflow=2 Alexander Motzkau
2021-03-06 11:23 ` Andrew Haley
2021-03-06 12:03   ` Alexander Motzkau
2021-03-07 11:37     ` Andrew Haley
2021-03-07 14:04       ` Alexander Motzkau
2021-03-07 14:56         ` Andrew Haley
2021-03-08 16:43           ` Segher Boessenkool
2021-03-07 15:31         ` Ian Lance Taylor
2021-03-08 21:05         ` Martin Sebor
2021-03-08 21:57           ` Alexander Motzkau
2021-03-09  9:09           ` Andrew Haley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).