2

I've compiled simple UB code without any warnings or errors using Visual Studio 2019:

int main()
{
    int i = 10;
    i = i++ + ++i;
    return i;
}

I've turned on EnableAllWarnings(/Wall) and treat warnings as errors(/WX) flags. It compiled into:

mov         eax,17h  
ret  

Because compiler generated this code, I'm sure that he detected UB. Why doesn't MSVC generates any warning about UB?

I've checked that Clang and GCC gives warnings for this example. Do they generate warnings for any possible UB? If so, why MSVC doesn't?

4
  • 3
    In case of undfined behaviour the compiler is allowed to do, what he wants Commented Jan 29, 2020 at 14:58
  • 8
    Compilers are not required to report UB. Commented Jan 29, 2020 at 14:58
  • 2
    And what makes you sure that it "detected" the UB? 23 (decimal) doesn't seems like any special value for it to have been detected. Commented Jan 29, 2020 at 15:00
  • 1
    The compiler did not detect undefined behavior. It calculated the result at compile time since it was a simple expression which it optimized out. Since the calculation was undefined behavior the result can be anything. Commented Jan 29, 2020 at 15:08

3 Answers 3

4

Clang and GCC gives warnings for this example. Do they generate warnings for any possible UB?

No. Many things are defined as "undefined behavior" instead of requiring a diagnostic, exactly because they are extremely difficult (or even theoretically proven to be impossible) to detect with 100% accuracy.

Sign up to request clarification or add additional context in comments.

1 Comment

Not only that, but the mistakes that would be easiest to detect are often those programmers would be least likely to actually make.
1

in clang you can use like that:

clang++ -fsanitize=undefined test.cpp

When the program runs, it will report errors like that

visual studio already supports address_sanitizer. It seems that UndefinedBehaviorSanitizer will have to wait a while

Comments

0

Suppose the code had been *p = (*q)++ + ++(*r); In that case, a compiler would generally have no way of knowing which if any combinations of pointers would be identifying the same objects. While it would be simple to make a compiler issue a diagnostic in simple code snippets like yours, the likelihood of anyone accidentally writing such code would be rather remote compared to the likelihood of failing to separate operations on pointers that happen to identify the same objects. A compiler isn't going to issue a diagnostic for a construct unless the author or maintainer writes code to do so. While some compilers' writers spend a lot of effort including such diagnostics, many others judge that any time and effort they could have to spend including such diagnostics would be better spent on supporting other, more useful, features.

11 Comments

And then there are the more surprising implications of undefined behavior, such as that if the compiler is written to recognize possible undefined behavior in (*q)++ + ++(*r) what it's likely to do is note that undefined behavior occurs when *q overlaps *r, and the programmer is responsible for avoiding UB, therefore *q does not overlap*r. And there it can proceed to optimize other (correct) code in ways that are not safe when q == r because it's already "proven" a lack of aliasing.
@BenVoigt: Indeed. The Standard makes no effort to judge what kinds of behavioral guarantees would make implementations more or less suitable for various purposes, but instead relies upon compiler writers to recognize whatever guarantees their customers would find useful. Because some implementations are used in contexts where it would be impossible for a program to behave in worse-than-useless fashion, the Standard makes no attempt to mandate that implementations behave in ways that would be unsuitable for programs that process untrustworthy data in contexts where...
...some possible program behaviors (like letting the creators of malicious data take control over the machine) would be intolerable. Note that contrary to what the makers of clang and gcc claim, Undefined Behavior means nothing more nor less than that the Committee views some construct as outside its jurisdiction. In some cases, the Committee has even said how it expects some actions to be processed by commonplace implementations despite the lack of an actual requirement that any implementations behave in such fashion.
It's not just the construct causing UB that's outside the Standard's jurisdiction, but the behavior of the entire program which executes that construct. And the Standard is specific on that point.
@BenVoigt: According to the authors of the Standard, "It [undefined behavior] also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior." While programs exploiting such extensions may be non-portable, and their behavior is outside the Standard's jurisdiction, the authors of the Standard explicitly recognize that C programs are not required to be portable, and that one one of the strengths of C is the ability of non-portable code to do things that might not otherwise be possible.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.