The dangers of the 'const' qualifier

(Comments)

Which approach is right? GCC or ICC one?

"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

Currently unrated

Comments