This question already has an answer here:
I found this problem in a very large application, have made an SSCCE from it. I don't know whether the code has undefined behavior or -O2
breaks it.
When compiling it with gcc a.c -o a.exe -O2 -Wall -Wextra -Werror
it prints 5.
But it prints 25 when compiling without -O2
(eg -O1
) or uncommenting one of the 2 commented lines (prevent inlining).
#include <stdio.h>
#include <stdlib.h>
// __attribute__((noinline))
int f(int* todos, int input) {
int* cur = todos-1; // fixes the ++ at the beginning of the loop
int result = input;
while(1) {
cur++;
int ch = *cur;
// printf("(%i)\n", ch);
switch(ch) {
case 0:;
goto end;
case 1:;
result = result*result;
break;
}
}
end:
return result;
}
int main() {
int todos[] = { 1, 0}; // 1:square, 0:end
int input = 5;
int result = f(todos, input);
printf("=%i\n", result);
printf("end\n");
return 0;
}
Is GCC's option -O2
breaking this small program or do I have undefined behavior somewhere?
invokes undefined behavior.
todos - 1
is an invalid pointer address.Emphasis mine:
In supplement to @ouah's answer, this explains what the compiler is doing.
Generated assembler for reference:
However if I add a
printf
inmain()
:Specifically (in the
printf
version), these two instructions populate thetodo
arrayThis is conspicuously missing from the non-
printf
version, which for some reason only assigns the second element: