4 ms·
> But there are better and worse things compilers can do in the presence of UB, and the big one is warning you about it when it possibly can. The problem is th
by Denvercoder9 4y ago
> But there are better and worse things compilers can do in the presence of UB, and the big one is warning you about it when it possibly can.
The problem is that this is really hard to do without producing either too much or too little warnings, as undefined behaviour is usually input-triggered; and the compiler usually doesn't know all constraints on the arguments that the programmer knows about.
For example, the function f() in the article of the other discussion is perfectly well-defined for any argument x <= 0x402010, as in that case no overflow happens. The compiler doesn't know whether all callers ensure the argument is valid (e.g. this might be a library function, or the invariants might not be expressable in a way the compiler can understand). This is a lose-lose situation for the compiler: it can warn, but people will find the unnecessary warnings annoying and turn them off, while if it doesn't warn people will complain about perceivedly bad optimizations.
Of course there's a point to be made that the real problem here is that the C standard makes signed integer overflow undefined behaviour, but that's not gcc's fault and can be easily worked around with -fno-strict-overflow or -Wstrict-overflow.
- xg15 4y ago> This is a lose-lose situation for the compiler: it can warn, but people will find the unnecessary warnings annoying and turn them off, while if it doesn't warn people will complain about perceivedly bad optimizations. This could still be greatly alleaviated with the use of asserts: A compiler could default to the most conservative set of assumptions for an input value - e.g. that a parameter of a global function assumes the full value range of its type - unless the programmer provides more assumptions through an assert statement. In debug builds, you could compile those asserts to actual runtime checks, so the program can be appropriately tested. Then, in production builds, the asserts would simply be skipped. The second improvement would be warnings about "nonensical" statements (from the compiler's POV) that will be optimised away. E.g., many of the most egregious examples of UB are from code where the programmer inserted a bounds check to protect against UB at another location - and then the compiler optimized away that same bounds check as a "nasal demon" action, caused by the UB it was supposed to protect against. In those cases, it would be useful to warn "hey, this bounds check can never fail because that other statement implies that either we're in bounds or there is UB. You might want to check for UB here."
- vintermann 4y agoWe're re-litigating that other thread... but the function in the other thread had a conditional (trying to check for overflow after the fact) which would never be true, regardless of x. And it could statically prove this. And that proof, the compiler then decided to use to remove the code, ignoring the red flag that the programmer undoubtedly had tried (and failed!) to achieve something with it. I would have preferred a warning here. I don't turn off "condition is always true"-type checks.
- Denvercoder9 4y agoWhile I agree that in general a warning about "condition is always true/false"-style checks is useful, it's also a bit tricky to do without false positives. With macros and inlining (and in C++, templates) you can easily end up with conditionals of which any given instance is always true or false, but that aren't superfluous. Portability is another example. Depending on your environment and code style hitting these might be exceptional and warning-worthy, or something that happens all over the place.
- vgatherps 4y agoI also see this come up a lot in code generation and simd code. On the code generation it's way easier to just push all optimizations to the compiler, including constant propagation (i.e. easier to just mark an upstream boolean as constexpr true, instead of adding your own constant propagation). For simd it's common in my experience to do lots of (if size > X), where size and X are both known at compile time but might vary by target.