One of my hobbies in GDB is cleaning things up. A lot of this is modernizing and C++-ifying the code, but I’ve also enabled a number of warnings and other forms of code checking in the last year or two. I thought it might be interesting to look at the impact, on GDB, of these things.
So, I went through my old warning and sanitizer patch series (some of which are still in progress) to see how many bugs were caught.
This list is sorted by least effective first, with caveats.
-fsanitize=undefined; Score: 0 or 10
You can use
-fsanitize=undefined when compiling to have GCC detect undefined behavior in your code. This series hasn’t landed yet (it is pending some documentation updates).
We have a caveat already! It’s not completely fair to put UBsan at the top of the list — the point of this is that it detects situations where the compiler might do something bad. As far as I know, none of the undefined behavior that was fixed in this series caused any visible problem (so from this point of view the score is zero); however, who knows what future compilers might do (and from this point of view it found 10 bugs). So maybe UBSan should be last on the list.
Most of the bugs found were due to integer overflow, for example decoding ULEB128 in a signed type. There were also a couple cases of passing
memcpy with a length of 0, which is undefined but should probably just be changed in the standard.
-Wsuggest-override; Score: 0
This warning will fire if you have a method that could have been marked
override, but was not. This did not catch any gdb bugs. It does still have value, like everything on this list, because it may prevent a future bug.
-Wduplicated-cond; Score: 1
This warning detects duplicated conditions in an if-else chain. Normally, I suppose, these would arise from typos or copy/paste in similar conditions. The one bug this caught in GDB was of that form — two identical conditions in an instruction decoder.
GCC has a related
-Wduplicated-branches warning, which warns when the arms of an if have identical code; but it turns out that there are some macro expansions in one of GDB’s supporting libraries where this triggers, but where the code is in fact ok.
-Wunused-variable; Score: 2
When I added this warning to the build, I thought the impact would be removing some dead code, and perhaps a bit of fiddling with
#ifs. However, it caught a couple of real bugs: cases where a variable was unused, but should have been used.
-D_GLIBCXX_DEBUG; Score: 2
libstdc++ has a debug mode that enables extra checking in various parts of the C++ library. For example, enabling this will check the irreflexivity rule for
operator<. While the patch to enable this still hasn’t gone in — I think, actually, it is still pending some failure investigation on some builds — enabling the flag locally has caught a couple of bugs. The fixes for these went in.
-Wimplicit-fallthrough; Score: 3
C made a bad choice in allowing switch cases to fall through by default. This warning rectifies this old error by requiring you to explicitly mark fall-through cases.
Apparently I tried this twice; the first time didn’t detect any bugs, but the second time — and I don’t recall what, if anything, changed — this warning found three bugs: a missing break in the process recording code, and two in MI.
-Wshadow=local; Score: 3
Shadowing is when a variable in some inner scope has the same name as a variable in an outer scope. Often this is harmless, but sometimes it is confusing, and sometimes actively bad.
For a long time, enabling a warning in this area was controversial in GDB, because GCC didn’t offer enough control over exactly when to warn, the canonical example being that GCC would warn about a local variable named “
index“, which shadowed a deprecated C library function.
However, now GCC can warn about shadowing within a single function; so I wrote a series (still not checked in) to add
This found three bugs. One of the bugs was found by happenstance: it was in the vicinity of an otherwise innocuous shadowing problem. The other two bugs were cases where the shadowing variable caused incorrect behavior, and removing the inner declaration was enough to fix the problem.
-fsanitize=address; Score: 6
The address sanitizer checks various typical memory-related errors: buffer overflows, use-after-free, and the like. This series has not yet landed (I haven’t even written the final fix yet), but meanwhile it has found 6 bugs in GDB.
I’m generally a fan of turning on warnings, provided that they rarely have false positives.
There’s been a one-time cost for most warnings — a lot of grunge work to fix up all the obvious spots. Once that is done, though, the cost seems small: GDB enables warnings by default when built from git (not when built from a release), and most regular developers use GCC, so build failures are caught quickly.
The main surprise for me is how few bugs were caught. I suppose this is partly because the analysis done for new warnings is pretty shallow. In cases like the address sanitizer, more bugs were found; but at the same time there have already been passes done over GDB using Valgrind and memcheck, so perhaps the number of such bugs was already on the low side.