251: What Happens When Code Has Undefined Behavior?
Take Up Code - A podcast by Take Up Code: build your own computer games, apps, and robotics with podcasts and live classes
Categories:
What happens when code has undefined behavior? There’s hundreds of ways code can have undefined behavior. What happens is completely up to the compiler. You should not depend on undefined behavior because compilers can completely change or delete sections of code. Since the behavior is undefined, then compilers can optimize code in ways you never intended. I’ve known about undefined behavior for a long time. But this episode describes something that surprised me. I was not fully aware of the magnitude of the problem and the drastic steps that compilers can take. You really can’t depend on anything in your code once you enter undefined behavior. And because compilers are getting better all the time, something that used to go undetected can suddenly change on you as the compiler decides to rewrite your code. Since it’s already undefined, then who’s to say that the compiler is wrong? There’s a lot of really great videos online at cppcon.org about undefined behavior if you want to learn more. Just search for “cppcon undefined behavior” and you’ll find lots more information. If you’d like to improve your coding skills even more, then you can find all my favorite books and resources at the Resources page. Listen to the full episode for more details or read the full transcript below. Transcript Undefined means that we don’t know what will happen. I’ve been programming for a long time and have known about undefined behavior. But I just learned something new about undefined behavior that I want to share with you. This surprised me. Let’s first recap what is undefined behavior and what causes it. You can get into this situation in a lot of ways. I recently found out that the C language has about 200 documented cases leading to undefined behavior in your code. C++ has even more but they’re not documented all in one place. None of this includes your own code or that of some library you’re using. I’ve always known that you can’t rely on undefined behavior but what surprised me was that the compiler can decide to do whatever it wants when it detects undefined behavior. Since the behavior is already undefined, the compiler writers viewpoint is that the compiler can’t make things any worse. So what happens is the compiler can optimize your code. In other words, they actually use undefined behavior. And compilers don’t just use undefined behavior in the same way, they’re getting better at it. Code that used to work even though it relied on undefined behavior can sometimes stop when you upgrade your compiler. A new compiler can detect the undefined behavior and decide to reorder your code, skip function calls completely, exit out of your loops early, and who knows what else. The exact code generated by the compiler can change from one version to the next or even with different options. Compilers are able to detect undefined behavior based on possible misuse even if other factors would normally cause nothing bad to happen. For example, there’s a method called memcpy, usually pronounced as “memcopy”, that copies data from one place in memory to another. It takes two pointers and an integer. One pointer points to the source of the data. Another pointer points to the destination. And the integer lets you control how much data will be copied. Now, if you call this method with the size set to zero, then it doesn’t matter what the source and destination point to. You’re saying don’t copy anything from over there to over here. But just the fact that the compiler notices you using null pointers means you’ve already entered undefined behavior. To put this in terms of something from real life, let’s say that you visit an ice cream shop and tell the clerk that you’d like to purchase nothing. Does it really matter if you wanted to pay with fake monopoly money? No. Because you’re