4

I would like to add a CXXFLAG to my build systems that force the entire code-base to be well-defined. So every piece of code that exhibits undefined behaviour in a static fashion, should be refused by the compiler.

For instance reinterpret_cast<A*>(someIntPtr)->aMember is without any runtime context undefined (a), while int i = bar(); i /= i; could result in undefined behaviour (b) depending on the runtime evaluation of bar() (which could return zero).
I only expect the (a) cases to be caught, not necessarily the (b) cases.

bitmask
  • 32,434
  • 14
  • 99
  • 159
  • 1
    Maybe it could catch `i /= i` too, since if it's not undefined behavior, it's just a silly way to say `i = 1`. – Benjamin Lindley Dec 20 '11 at 02:50
  • 1
    The answers to [A C++ implementation that detects undefined behavior?](http://stackoverflow.com/q/7237963/2509) address what can be done with g++ in this direction. – dmckee --- ex-moderator kitten Dec 20 '11 at 02:51
  • @Benjamin Lindley: `i/i` is not a silliy way to say `1` because `i/i` is undefined iff `i == 0`. In all other cases, you are right, it is `1`. – bitmask Dec 20 '11 at 14:13
  • @bitmask: Isn't that the gist of what I said? *"if it's not undefined behavior"* i.e. *"except in the case where it is undefined behavior"* i.e. *"except when i is zero"* – Benjamin Lindley Dec 21 '11 at 01:45
  • @Benjamin Lindley: Whoops, I overlooked the "*if*" which changes the meaning completely :) – bitmask Dec 21 '11 at 01:52
  • With undefined behavior sanitizers the answer to this question changes a bit, although the are run-time checkers they catch a lot of non-trivial UB. Also constexpr can help a bit here depending on the use cases. – Shafik Yaghmour Oct 17 '14 at 12:55

4 Answers4

7

I'm not sure that your goal is computationally feasible.

However, you'll get moderately close with -Wall -Wextra -Werror; look at the other warning options to see what else you want to enable.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • As @Kerrek has said, the compiler will miss many cases, but +1 to Jonathan for being constructive and giving the best options available. I would also run the program with valgrind to help detect any memory access troubles that do leak into the final executable. – ams Dec 20 '11 at 21:46
6

Impossible. There are many, many instances of UB which are not detectable. That's arguably the reason why they are UB, exactly because it is impossible to catch these problems at compile time.

Some examples:

  • int n = 0; std::cin >> n; ++n; Signed overflow is UB. (Example of value-dependent UB.)

  • double d = std::sin(some_user_value); int n = d; UB if d cannot be represented as an int. (Ditto.)

  • compile multiple translation units with differing class definitions visible to each. (Example of UB due to limitations of the compilation model.)

  • any race condition is by definition UB. (Example memory-model related UB.)

  • misuse of variadic functions. (Example of UB due to the type system.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Of course it's undecidable in general (halting problem). That's why I added the second paragraph; Detect all static cases. – bitmask Dec 20 '11 at 09:00
  • "`int n; std::cin >> n; ++n;`" Without error checking, there is a potential for UB here, unless it can be assumed that the input operation succeeds. – curiousguy Dec 20 '11 at 23:05
  • Again, the error checking is missing, which is a programming error and can cause UB, unless you can assume that the formatted read operation succeeds. – curiousguy Dec 20 '11 at 23:14
  • @curiousguy: I fixed that by initializing `n`. – Kerrek SB Dec 21 '11 at 14:46
1

You can use static code analysis tools similar to the classic lint. You may already have cppcheck.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
1

You can't, and you shouldn't rely on the compiler to point out UB for you.

You best bet is to use -Werror to cause all warnings to become errors, and then enable a great deal of warnings.

Pubby
  • 51,882
  • 13
  • 139
  • 180