Hacker News new | ask | show | jobs
by blue_pancake 2757 days ago
Undefined behavior gets a bad rap, but it's not always evil. Compilers and executables would be a lot slower if they had to account for these cases.

If you're writing serious C, you should be using tools like valgrind on debug-mode executables to make sure you aren't relying on undefined behavior. The tools are there. It's just not something a lot of people do.

1 comments

My instinct is to downvote this to keep it at the bottom of the page, but since you are a new user with seemingly good intentions, that seems too rude.

Undefined behavior gets a bad rap, but it's not always evil.

Probably true, but make sure that you are distinguishing between undefined and implementation defined.

Compilers and executables would be a lot slower if they had to account for these cases.

Maybe, but I'd like to see better quantification for "a lot". My instinct (unsourced) is that it's usually minimal for most C, and quite significant for templated C++. But I'd interested in seeing firm numbers on this.

If you're writing serious C, you should be using tools like valgrind on debug-mode executables to make sure you aren't relying on undefined behavior.

This is where I think you veer off into being mostly wrong. I grew up with Valgrind, but I don't think it really has much use any more. You are almost always better off with one of the now built-in "sanitizers": https://github.com/google/sanitizers/wiki/AddressSanitizerCo....

But while you should be using these to catch bugs, neither the sanitizers nor Valgrind are able to catch the dangerous forms of undefined behavior shown in the examples in the article. UBSan is great and should be more used than it is (https://medium.com/@lucianoalmeida1/the-undefined-behavior-s...) but it is not going to catch anything near all the problems with undefined behavior!

Here's a summary of the unfortunate state of the art: https://blog.regehr.org/archives/1520. While there are underutilized tools that can help, "using tools like valgrind on debug-mode executables to make sure you aren't relying on undefined behavior" is likely to give you misplaced confidence that you are free from the dangers.

> But I'd interested in seeing firm numbers on this.

From Regehr's blog post that you linked:

> An issue with mitigating integer UBs is the overhead. For example, they cause SPEC CPU 2006 to run about 30% slower.

I think this is the overhead for mitigating by adding additional code (a branch on overflow that can be predicted as not taken), rather than the cost of lost optimizations that could have been used by assuming that UB does not occur. So a useful number, but measuring something else.

Although perhaps it can be used an an upper bound on the boost provided UB-free optimizations? That is, the overflow checking has both a direct cost, and prevents certain beneficial optimizations. Thus we can assume that the optimization benefit (on SPEC CPU 2006) is something less than 30%. That is to say, real, but not enormous compared to an algorithmic difference.

> I think this is the overhead for mitigating by adding additional code

I think so too - as OP just said "dealing with," it wasn't clear to me that you were talking about just ignoring rather than handling.

I don’t have numbers but I if imagine you forced the compiler to assume that any two pointers, regardless of type, could alias unless it could be proven otherwise, many of the optimizations that reduce or eliminate the cost of repeated indirection through a pointer could no longer be applied.