ellipsix informatics
 
 
Trackback URI
2014
Nov
24

On compiler warnings (and off them, too)

Bookmark and Share

Quick, what's wrong with this C++ program?

#include <iostream>

int test(int arg) {
    cout << arg << endl;
}

int main(int argc, char** argv) {
    test(5);
}

Did you guess nothing at all? Because that's what GCC says:

$ g++ -o funnyprogram funnyprogram.cpp
$

WTF.

Pretty much every other programming language that makes you explicitly identify a function's return type will also make you actually return something from that function. C and C++ don't, and furthermore GCC doesn't even warn you that anything is wrong. This can occasionally lead to serious bugs, as I discovered today in this real-world example. I had a function that checks the name of an object and returns an enum value based on that name.

virtual const HardFactorOrder get_order() const {
    // relies on a particular convention for get_name()
    // but can be overridden for hard factors where that convention doesn't apply
    std::string name = get_name();
    if (name.compare(0, 3, "H01") == 0) {
        return MIXED;
    }
    else if (name.compare(0, 2, "H0") == 0) {
        return LO;
    }
    else if (name.compare(0, 2, "H1") == 0) {
        return NLO;
    }
};

That was all good when all the objects involved had names conforming to the convention, but my latest batch of updates to the code involve objects with totally different names, and I forgot to override get_order(). So the default implementation above was getting used. Instead of failing with an error when none of the patterns matched, it was just not returning anything, and the variable that I set the return value to was getting assigned some random binary nonsense. Something like 2692389, where the legal values were 0, 1, and 2.

Needless to say, if GCC had complained about this from the start, I wouldn't have spent at least an hour staring at tiny text in a debugger.

tiny text in a debugger

There are over a hundred warnings that GCC can be configured to emit. Some of them are relatively useless, but most probably should be enabled if you want to save yourself a lot of debugging time. I pored through the manual and came up with the following set of warnings for myself:

-Wall -Wextra -Wformat-security -Wmissing-include-dirs -Wuninitialized
 -Wtrampolines -Wconversion -Wuseless-cast -Wjump-misses-init -Wlogical-op
 -Wstrict-prototypes -Wctor-dtor-privacy -Wold-style-cast -Wno-reorder
 -Wno-unused-parameter -Werror=delete-non-virtual-dtor -Werror=return-type
 -Werror=implicit

That's quite a mouthful, though a build system like Cmake can handle it easily; just copy and paste into the appropriate spot in the configuration file. For times when you invoke GCC manually, you can put those options in a file, perhaps ~/Wreally-all, and then run

g++ @/home/user/Wreally-all -o program program.cpp ...

which will include the contents of the file as if you had specified it on the command line.

Feel free to use this as a starting point for figuring out what set of warnings is most useful for your own environment.

blog comments powered by Disqus