For illustrative purposes, I have been trying to find an example, by using gcc, where the output of a program is different with and without optimization enabled (with and without -O3
). The purpose of finding such example is to show how optimizations could make an apparently correct program behave different after optimizations have been active if the code contains undefined behaviour.
I have been trying different "combos" of the following program:
// I have tried defining blind in this and in a separate module. The result is the same.
void blind(int const* p) { ++*const_cast<int*>(p); }
#include <iostream>
int constant() { return 0; }
int main()
{
int const p = constant();
blind(&p);
std::cout << p << std::endl;
return 0;
}
I was expecting that, without optimizations enabled, this program will show 1, but with optimizations enabled (-O3
) it will show 0 (by replacing std::cout << p
by std::cout << 0
directly), but that's not the case. If I replace the initialization by int const p = 0
, it will print 0
with and without optimizations enabled, and so the behaviour is again the same.
I have tried different alternatives like doing arithmetic operations (expecting the compiler to prefer to "pre-compute" the value or something), calling blind
several times, etc. But nothing works.
NOTE: Preferably, one example where the program won't probably crash in the optimized version.
A nice and very simple case that matches the kind of example I was looking for is the following:
#include <iostream>
#include <climits>
bool check(int i)
{
int j = i + 1;
return j < i;
}
int main()
{
std::cout << check(INT_MAX) << std::endl;
return 0;
}
Without optimizations enabled, check
returns 1
, because overflow did happen. With optimizations enabled, even with -O1
, check
returns 0
.
I started with:
#include <iostream>
#include <climits>
bool check(int i)
{
return i + 1 < i;
}
int main()
{
std::cout << check(INT_MAX) << std::endl;
return 0;
}
Since signed integer overflow is UB, the compiler directly returned 0
without performing the actual comparision even without optimizations enabled:
Since the behaviour was still the same with and without optimizations, I decided to move the calculation of i + 1
to a new variable j
:
bool check(int i)
{
int j = i + 1;
return j < i;
}
Now, the compiler, in a non-optimized build, is forced to actually calculate j
so the variable can be inspected with a debugger, and the comparision is actually performed, and that's why it returns 1
.
However, with -O1
, the compiler translated check
to its equivalent form return i + 1 < i
, which becomes return 0
as in the previous variation of the program.