Birth and death of an Heisenbug
Posted on
I came across a weird C++ line of code that I wanted to share, although it does not deal with fast C++. For the sake of simplicity, I dropped all the fancy data structures and replaced them with plain old data types. It goes like this :
int a, b; a, b = 5, 6; cout << a << endl; // a random value is printed!
The code was written by a young developer who is quite knowledgeable about C++17 and Python. And in fact Python allows that sort of comma-separated assignment. In C++, it compiles fine with our release flags, where there is no warning enabled. In our debug compilation setup, specifically with the -Wall flag, it produces the following warning at the first line where the variable 'a' is read:
warning: 'a' is used uninitialized in this function [-Wuninitialized]
I tested this with GCC 4.8.1. The thing is that our debug flags are so extensive that there are literally tons of warnings. So much that people simply don't pay attention to the build outputs anymore! As a side note, those warnings are not necessarily from our codebase. But rather from the third party libraries' headers we compile against. That important warning about the uninitialized variable therefore remained unnoticed, lost in the middle of the massive compiler outputs. The uninitialized variable manifested as an Heisenbug, a random crash. The type of problem I am the most worried about. The ones that highlight poor code quality. The developer could not find the origin of the crashes, and asked me for help. But the crashes occurred at random places, and quite far from the guilty line of code! Finding the source of the problem was such a pain. I may write a post in the future to explain my precise walkthrough. The key tool that helped me is Valgrind. Specifically the Memcheck tool, with the '--track-origins=yes' option, ran on a debug build of the program. It yielded the following information:
"Conditional jump or move depends on uninitialized value(s)"
Together with the full stack trace, including all files and lines of code involved. This led me to the culprit! My advice would be addressed to developers navigating across C++ and Python. While C++ has gotten alot easier to write in an ongoing effort right from C++11, it does not share the exact same principles than Python. Another advice would be to restrict the debug compilation flags to those which really influence code quality. Reducing the number of flags will accelerate compilation duration, and make important warnings stand out. Work on your building suite to let the compiler help you out as much as possible!