Is there a way to detect it dynamically, e.g. by running C code under a debug mode or in an interpreter that errors out when undefined behavior is encountered? I've occasionally wanted to have something like that to use in tests, so I could ensure that at least my common code paths aren't relying on undefined behavior. I know about gcc's -ftrapv and a few other options, but nothing comprehensive.
- KCC : high overhead, for all kinds of undefined behavior, limited standard library support (and source-level only)
- Valgrind : medium overhead, for various memory errors, binary, may fail to detect undefined behaviors that have been made undetectable by compilation.
You may also find:
- various memory-safe C compilers. There are plenty here, I had better let you do the googling. medium overhead, generally better than Valgrind at being sound (since they work at source level), unless they trade efficiency for soundness: http://research.microsoft.com/pubs/101450/baggy-usenix2009.p... . May require all source code to be available.
- Frama-C's value analysis, a static analyzer that can be used as a C interpreter. This is what I work on. Limitations comparable to KCC, quite a bit faster (but still high overhead), some slightly different design choices. I do not have a good single write-up for this use, but some details are available at these URLs:
In theory, for sure. Valgrind can test for certain kinds of undefined behaviour - it runs the code in a special virtual machine.
You could also have the compiler insert checks. Obviously this isn't desirable for a lot of C projects by default, but (other than in places like kernel development etc.) it could be a nice debugging aid. I don't know of any good tools for doing this comprehensively.
But the the author of the original piece is mostly concerned with undefined behavior that can be detected statically - otherwise, compilers would not be able to exploit it to make optimizations.
One thing he mentions is signed integer overflow. This is in the worst case equivalent to the halting problem, but even in practice very hard to test for at compile time.
Another behaviour he mentions is not properly return'ing at the end of a non-void function. This is again technically equivalent to the halting problem, but it is negated by the good practice of making every code path (even potentially dead ones) have a return statement (or throw an exception, etc.) Go takes this approach if I remember correctly.
It can't always be tested for at compiler time but the problem he's complaining about is when C compilers do detect signed integer overflow. What happens is that someone writes code that in practice handles signed integer overflow fine, then a while later the C compiler developers get clever, detect the integer overflow, and decide to optimize that code away because it's invoking undefined behaviour and they can do whatever they like. The code in question is frequently security-critical, so by removing it the compiler converts safe code whose behaviour is technically undefined by the standard into a security vulnerability.
The common case is (probably) not that a compiler detects an instance of signed over/underflow. Instead, it can assume that this never happens and generate "dangerous" code.