4
#include <iostream>

int main()
{
    int n = -1000;
    for (int i(0); i != n; ++i)
    {
    }
}

In gcc the following error is caught at compile-time:

main.cpp:6:5: warning: iteration 2147483647u invokes undefined behavior [-Waggressive-loop-optimizations]

     for (int i(0); i != n; ++i)

Clang's -fsanitize=undefined is a run-time mechanism. What is clang's compile-time equivalent?

Lrrr
  • 4,755
  • 5
  • 41
  • 63
user4172851
  • 41
  • 1
  • 2
  • 1
    That seems to be a very recent feature of GCC (it's in 4.9, but not 4.8). I wouldn't be surprised if Clang doesn't have it yet. And of course, many instances like this can't be caught at runtime; this only works because the value of `n` is known during compilation. – Mike Seymour Oct 23 '14 at 07:38
  • `-Wall` would catch things that lead to UB at compile-time as a warning. – Rapptz Oct 23 '14 at 07:38
  • @Rapptz yet it doesn't for this case, and that is the, admittedly ultra specific, question. – rubenvb Oct 23 '14 at 07:39
  • I don't think there is one. Take a look [at why LLVM does not produce compiler warnings](http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html) – Daniel Oct 23 '14 at 07:42
  • @simpleBob: This particular one could be caught, I'm sure. But yes, it does get very complicated to track ALL of these things. – Mats Petersson Oct 23 '14 at 07:53

2 Answers2

6

Undefined behaviour is often described as such in the standard because it is difficult if not impossible for the compiler to check this in all situations.

You just run into one case that is handled by GCC and not Clang. If you look, you'll be able to find cases that are handled by one but not another compiler. That's because they're not the same compiler, and have different analyses that they perform.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • 5
    And indeed that's a good reason to compile your code with multiple compilers in order to pick up more problems at compile-time. – Stuart Golodetz Oct 23 '14 at 07:44
4

Clang can't catch this one yet, at least not as part of compiling (I haven't checked the clang static analyzer, and if it also can't, please file a bug).

GCC has decided that it's okay to emit warnings from the middle of the optimizer:

$ g++ -Waggressive-loop-optimizations a.cc
$ g++ -Waggressive-loop-optimizations a.cc -O2
a.cc: In function ‘int main()’:
a.cc:6:5: warning: iteration 2147483647u invokes undefined behavior [-Waggressive-loop-optimizations]
     for (int i(0); i != n; ++i)
     ^
a.cc:6:5: note: containing loop

This is actually really tricky and potentially finicky. The clang developers believe that changing what warnings you emit based on optimization level is bad behaviour, we don't think users expect to miss warnings when building at -O0 or to discover new bugs days later when doing a release build. Secondly, the way that the optimizer is designed is such that it keeps one representation of the program around at any point in time and transforms it from saying one thing to another without keeping a history trail of what it's done versus what's in the original code. This LLVM blog article talks about the problem. Clang's warnings are built on top of clang's ASTs which have a complete representation of the original source code, including template and macro histories so we can always point to the right code and filter on properties like "was it a template argument".

It might be possible to add this to clang, I haven't figured out an efficient way to do it after only 30 seconds of thinking about it. The problem is that we're willing to spend a lot more time proving things in the optimizer than we are as part of warning generation. We don't want to pay the compile time twice. The static analyzer on the other hand, doesn't have this restriction and will happily do very expensive work to find your bugs.

Finally, the way you phrased your question makes it sound like you think that clang either does or doesn't catch all undefined behaviour at compile time. We do catch as much as we can efficiently, and provide dynamic checkers for as much of the rest as possible, but neither gcc nor clang will promise to catch all undefined behaviour either at compile time nor at run time. There's too much of it, and there is no list of what it all is (some operations are explicitly UB in the standard, some are UB simply because the standard fails to define what the behaviour is!).

  • `Waggressive-loop-optimizations` is indeed finicky here [is a question](http://stackoverflow.com/q/32506643/1708801) where the structure of the code matter wrt to whether we get a warning or not. – Shafik Yaghmour Sep 13 '15 at 03:22
  • 2
    That's too bad. If the compiler can sometimes tell me that I have a bug in my code, I'd like for it to do so, even if it can't always tell me. – David Stone Mar 05 '16 at 17:50