(Comments)
"Undefined Behavior" is one of those frustrating aspects of the C Language. It leads to defensive programming and avoiding some of the coolest features of the language. Well, today I was struct, again, by such "undefinitions"...
A local declaration looked like:
struct some_struct * const var;
some_method(&var);
assert(var);
// do stuff with var...
Where some_method initialized the var;
All fine. GCC and CLang were happy with that, a constant whose initialization was postponed to a function call.
But, one day, I had to use the ICC (Intel C++ Compiler) and it complained about this uninitialized declaration. So I absent mindedly "fixed" it to:
struct some_struct * const var = NULL;
some_method(&var);
assert(var);
// do stuff with var...
It built fine, no errors, no warnings. Unit tests passed. Integration tests passed. So I pushed.
Minutes later CI dashboard gets red! Unit tests failed on Release build!
Of course I only tested the Debug build...
I made a RelWithDebInfo (Release with Debug Information) build and put GDB to work. As expected it skipped the `assert()` call, because it is dropped on Release builds, and the code below was getting a NULL in var. Checking `some_method` showed no way that `var` could be set to NULL. Where was that NULL coming from? The initialization.
In GCC, when compiling using Release mode, we use the `-O3' switch. With this switch on it seems that GCC optimizes out assignments to const values if they are initialized. So when I changed the declaration to include an initialization, GCC prevented the variable to be properly assigned. Of course, all those decisions are taken with NO WARNING issued.
Easy solution: remove the `const` qualifier:
struct some_struct *var = NULL;
some_method(&var);
assert(var);
// do stuff with var...
And now everything was again working... with all compilers.
Image by Pixaline from Pixabay
Share on Twitter Share on Facebook
Comments