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?

3 Answers3

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.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Not only that, but the mistakes that would be easiest to detect are often those programmers would be least likely to actually make. – supercat Jan 31 '20 at 17:46
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

Kargath
  • 450
  • 5
  • 15
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.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 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. – Ben Voigt Jan 31 '20 at 19:36
  • @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... – supercat Jan 31 '20 at 19:48
  • ...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. – supercat Jan 31 '20 at 19:49
  • 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. – Ben Voigt Jan 31 '20 at 20:01
  • @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. – supercat Jan 31 '20 at 20:06
  • Oh, we're meaning different things by "the Standard". This question's tagged [tag:c++]. – Ben Voigt Jan 31 '20 at 20:09
  • @BenVoigt: Given that C++ is derived from C, I would think that many actions which are classified as UB in both languages do so because they were first classified as UB in C89, making the reasons for the latter relevant to C++. Are you aware of any published rationale for the C++ Standard that would indicate a contrary intention? – supercat Jan 31 '20 at 20:57
  • I don't doubt that is correct, but "we inherited some cases of UB" doesn't imply that both language committees have the same philosophy about platform-specific treatment of programs containing undefined behavior. C++ does not seem to intend to permit platforms to define the behavior of some kinds of UB. Causing UB inside a `constexpr` evaluation results in a compile error, and [compliant compilers cannot redefine this](https://eel.is/c++draft/expr.const#4.7). – Ben Voigt Jan 31 '20 at 22:53
  • @BenVoigt: The C Standard defines a category of "strictly conforming" programs, but the authors did not intend to imply that all useful C programs should be made strictly conforming. The C++ Standard expressly declines to define any category of conforming programs. Both standards tend to have a bias toward eliminating corner cases in specification, even if those corner cases would otherwise be useful. If I were writing the rules for constant expressions, I would have required that they not contain UB of the listed forms *except* in cases where an implementation would... – supercat Feb 01 '20 at 16:36
  • ...document an expression as yielding a consistent value in all circumstances. Trying to specify whether the rule applied in cases like `(1 << 129) & 1` on an implementation that specified that `(1<<129)` would yield 0 or 2, chosen in Unspecified fashion, might have complicate the Standard, however, and thus the authors of the Standard thought it simpler to say that such expressions should always cause potential template substitutions to be rejected. [IMHO, it wouldn't have calculated it *much* to say that for something cannot be an Integer Constant Expression if there is any context... – supercat Feb 01 '20 at 16:43
  • ...in which replacing any operands with other expressions having the same numerical values could yield any side effects or a different result]. I think the intention is that the value of all constant expressions be fully specified, but I think there are a few corner cases involving floating-point values where that doesn't necessarily work. – supercat Feb 01 '20 at 16:49