Despite the age of your question, since you didn't change that part of your code yet, I assume the problem still exists and that you still didn't get a useful explanation on what's actually going on here, so let my try it:
In C (and C++), if adding two SIGNED integers causes an overflow, the behavior of the entire program run is UNDEFINED. So, the environment that executes your program can do whatever it wants (format your hard disk or start a nuklear war, assuming the necessary hardware is present).
gcc usually does neither, but it does other nasty things (that could still lead to either one in unlucky circumstances). To demonstrate this, let me give you a simple example from Felix von Leitner @ http://ptrace.fefe.de/int.c:
#include <assert.h>
#include <stdio.h>
int foo(int a) {
assert(a+100 > a);
printf("%d %d\n",a+100,a);
return a;
}
int main() {
foo(100);
foo(0x7fffffff);
}
Note: I added stdio.h, to get rid of the warning about printf not being declared.
Now, if we run this, we would expect the code to assert out on the second call of foo, because it creates an integer overflow and checks for it. So, let's do it:
$ gcc -O3 int.c -o int && ./int
200 100
-2147483549 2147483647
WTF? (WTF, German for "Was täte Fefe" - "what would Fefe do", Fefe being the nick name of Felix von Leitner, which I borrowed the code example from). Oh, and, btw, Was täte Fefe? Right: Write a bug report in 2007 about this issue! https://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475
Back to your question. If you now try to dig down, you could create an assembly output (-S) and investigate only to figure out, that the assert
was completely removed
$ gcc -S -O3 int.c -o int.s && cat int.s
[...]
foo:
pushq %rbx // save "callee-save" register %rbx
leal 100(%rdi), %edx // calc a+100 -> %rdx for printf
leaq .LC0(%rip), %rsi // "%d %d\n" for printf
movl %edi, %ebx // save `a` to %rbx
movl %edi, %ecx // move `a` to %rcx for printf
xorl %eax, %eax // more prep for printf
movl $1, %edi // and even more prep
call __printf_chk@PLT // printf call
movl %ebx, %eax // restore `a` to %rax as return value
popq %rbx // recover "callee-save" %rbx
ret // and return
No assert here at any place.
Now, let's turn on warnings during compilation.
$ gcc -Wall -O3 int.c -o int.s
int.c: In function 'foo':
int.c:5:2: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true [-Wstrict-overflow]
assert(a+100 > a);
^~~~~~
So, what this message actually says is: a + 100
could potentially overflow causing undefined behavior. Because you are a highly skilled professional software developer, who never does anything wrong, I (gcc) know for sure, that a + 100
will not overflow. Because I know that, I also know, that a + 100 > a
is always true. Because I know that, I know that the assert never fires. And because I know that, I can eliminate the entire assert in 'dead-code-elimination' optimization.
And that is exactly, what gcc does here (and warns you about).
Now, in your small example, the data flow analysis can determine, that this integer in fact does not overflow. So, gcc does not need to assume it to never overflow, instead, gcc can prove it to never overflow. In this case, it's absolutely ok to remove the code (the compiler could still warn about dead code elimination here, but dce happen so often, that probably nobody wants those warnings). But in your "real world code", the data flow analysis fails, because not all necessary information is present for it to take place. So, gcc doesn't know, whether a++
overflows. So it warns you, that it assumes that never happens (and then gcc removes the entire if statement).
One way to solve (or hide !!!) the issue here would be to assert for a < INT_MAX
prior to doing the a++
. Anyway, I fear, you might have some real bug there, but I would have to investigate much more to figure it out. However, you can figure it out yourself, be creating your MVCE the proper way: Take that source code with the warning, add anything necessary from include files to get the source code stand-alone (gcc -E
is a little bit extreme but would do the job), then start removing anything that doesn't make the warning disappear until you have a code where you can't remove anything anymore.