I came across a (for me) unexpected behavior of g++ (v 10.2.1). Here is a minimal example:
#include <iostream>
int f(int x) {
if(x==0) {
std::cout << "I am here" << std::endl;
return 5;
}
}
int main(int argc, char** argv) {
int x = f(atoi(argv[1]));
std::cout << x << std::endl;
return 0;
}
I am aware that the code does not make much sense, since f doesn't return a value if x is not 0. When I compile with g++ -Wall -O3 -DNDBUG -o bla bla.cpp
, the compiler also warns me about that, naturally. If I run the program anyway, the following happens:
$ ./bla 0
I am here
5
$ ./bla 1
I am here
5
$ ./bla 2
I am here
5
$ ./bla 3
I am here
5
I get it - the compiler sees that the only possible return is within the if-statement, so it removes the if statement. However, it took me hours to understand that in my actual (non-minimal) code: my function f had also an else-branch, but I commented it out for the purpose of testing a new feature, and then I got weird behavior because of this effect.
My question is whether this is a justifiable optimization or should rather considered as a bug in the compiler?
Edit: Thanks for the fast answers. Yes, as I said, I got the warning, too. I agree that one should take warnings seriously. But just to provide an example that is closer to what I actually had: I even ignore the return value in the function that calls f - the main "output" of the function is passed by reference, and the actual output is more of an additional value. So my (wrong) thinking was that it does not matter if the code returns a nonsense value as I won't need it (again, for testing purposes). I still find it strange that the example below changes it behavior if I replace "int f.." with "void f", and "return 5" with "return".
#include <iostream>
int f(int x,int& z) {
if(x==0) {
std::cout << "I am here" << std::endl;
z=7;
return 5;
}
}
int main(int argc, char** argv) {
int z=1;
f(atoi(argv[1]),z);
std::cout << z << std::endl;
return 0;
}
Output
$ ./bla 0
I am here
7
$ ./bla 1
I am here
7
$ ./bla 2
I am here
7
$ ./bla 3
I am here
7
Final edit: Thanks for the discussion. To summarize (if anyone reads this later): I thought that with a missing return at the end, just the return value of the function is undefined (which would be ok in the extended example). But in fact, the whole behavior of the function is undefined, which is much more than that.
My question is whether this is a justifiable optimization or should rather considered as a bug in the compiler?
It's justifiable. Compilers are allowed to assume that your program is written in such a way that undefined behavior doesn't occur and they are allowed to make optimizations based on that assumption.
If your program doesn't live up to it, the result can be very confusing, but that's the cost you'll have to pay in order to get good optimizations quickly when creating programs with defined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With