views:

667

answers:

16

In questions about things not to do in C++ such as dereferencing a dangling pointer or calling delete twice for the same address I often see the statement that it's undefined behaviour and anything can happen - the program can overwrite the system disk or offend my parents.

What is the worst real example of undefined behaviour consequences beyond crashing the program? I don't mean cases when first data in memory is corrupted and then this data is fed somewhere and that somewhere behaves wrong, I mean cases when undefined behaviour on its own directly causes bad consequences.

+1  A: 

I once accidentally delete'd a pointer twice and my computer collapsed into a singularity while flying monkeys extruded themselves from my nether regions.

Not really, but the whole point of undefined behavior is that it's, well, undefined.

This is not to be confused with defined behavior (which the standard mandates) or implementation-defined behavior (which the standard doesn't mandate but the implementation must).

The worst I've ever seen was wrong data being put into a variable which was later used (one of those "i = i++ + ++i;" moments). Nothing more serious than that unfortunately.

But bad data is serious enough, believe me.

paxdiablo
+1  A: 

"The disk can be overwritten" is kind of a joke (not a very great one but still), anyway, it is meant to emphasize the nature of the behaviour allowed for undefined operations, not necessarily the magnitude. Probably the worst result that you are ever going to see in the case of undefined behaviour is the kind of things that you would expect such as memory corruptions, hangs and so on. Although, this can lead to any kind of result in the end anyway, including maybe your harddrive being formatted, so maybe that is not such a low probability after all.

char *commandString="do something innocuous";
aFunctionWhichOverwritesTheAddressOfCommandStringToSomethingWhichFormatsTheHardDrive();
system(commandString);
1800 INFORMATION
+1  A: 

Well, I'd say it depends on the circumstances.

If undefined behaviour causes a missile to do unexpected things, offending your parents might be the least of your problems.

MyKey_
+2  A: 

What are the limits of your imagination?

Here's a few little disaster scenarios:

  • Overwriting a critical header in your binary file format just before you save to disk?

  • Rewriting part of another processes code in an unprotected environment?

  • Scribbling on memory mapped IO controller registers?

dmckee
+5  A: 

Broadly speaking...

In a modern PC, memory protection limits the direct damage to memory within the program's memory space. The damage could be proportionate to the privileges that process has while executing on a particular system (so don't run it with root privileges if you don't have to).

On the other hand, in embedded systems using a CPU without a memory management unit, a program could overwrite the entire processor memory space, which could easily corrupt a filesystem in use, mess up CPU or peripheral registers. Pretty much anything could go wrong.

The worst I've seen is a embedded device that had a fan speed controller. If code crashed, sometimes the fans would crank up to full-speed. Such things are mitigated with careful code review and testing, as well as defensive coding for things that really matter (e.g. the fan control software doing extra integrity checks of its variables and resetting if it finds an anomaly). Using "watchdog" circuit and/or software is also a standard practice.

Craig McQueen
Good point about watchdogs. Some PC BIOSes will set the fan speed to full when the system crashes due to a hardware failsafe/watchdog that detects when the power management code (ACPI? SMBIOS? not sure) stops running for more than a certain length of time. If a system failure could shut the fans off, the system would overheat and would be likely to damage hardware.
bk1e
+5  A: 

What is the worst real example of undefined behaviour consequences beyond crashing the program?

Crash (or lock up) the machine. Lose some data. Even, depending on the software, maybe toast some hardware.

FWIW as I developed a device driver for Windows 3.1 I used a diskless (i.e. without a hard drive) PC: instead it booted from floppy, loaded Netware client network drivers from the floppy, and then loaded Windows from a Netware file server. In those days (FAT, pre-NTFS) it was easy for a system crash to corrupt a local hard drive.

ChrisW
+11  A: 

In embedded code, without a "true" operating system to protect you from your mistakes, reading or writing from randomly-set pointers could realistically cause ANY behavior the device is physically capable of -- including launching nuclear missiles and causing Armageddon, I suppose, considering the quality standard of Pentagon procurement;-).

Alex Martelli
+19  A: 

The horror of undefined behavior isn't so much that the program will eat your homework, fire the nukes, or castrate you (though those are all certainly possible depending on the hardware your software is driving...) but that it is often very difficult to debug, and you will waste hours upon hours trying to figure out what went wrong after your program crashes or after you find it behaves differently on a new platform. Expressions with undefined behavior according to the language in question's standard will usually do one of the following annoying things:

  • Destroy the stack, meaning you can't get a backtrace.
  • Do something you don't want silently, so you don't know that something is wrong until much later; the further apart the moment when the problem is triggered from the moment when you can see its effects the more difficult it is to debug.
  • Behave differently under different compilers, so your program will seem to work fine on one platform but then break in unexpected ways when you try to port.

In an ideal language, anything that would have undefined behavior is a compiler error.

Joseph Garvin
In addition to potentially destroying the stack, it's possible in some language an undefined expression could confuse the garbage collector, but I'm not familiar enough with the implementations of any of the popular garbage collected languages to know how theoretical this is or isn't, so I leave that thought in this comment, all footnote like.
Joseph Garvin
+1: it can cause your program to crash *later*, 5 hours after the actual bug happened.
ChrisW
In theory, at least, it can also cause your program to crash *earlier*. Some expressions are stated to have undefined behavior when evaluated, but other conditions (a source file which is not terminated with a newline springs to mind) are stated to cause the *whole program* to have undefined behavior. I don't think I've ever come across any examples of this actually happening, so no use for this question, but I wouldn't state confidently that no compiler ever has output complete garbage in response to some such situtation.
Steve Jessop
I'm not sure your distinction makes sense -- if an expression has undefined behavior, doesn't that imply the whole program by virtue of containing that expression now has undefined behavior? Or maybe some languages distinguish between an expression having 'undefined behavior' versus an 'undefined value'? That is, if return value of an expression was undefined but was guaranteed to be a valid value for that type, I can see how it might not affect whether the whole program's behavior is defined.
Joseph Garvin
@Joseph: whether an expression has undefined behavior depends on the values involved. For example, `z=x/y;` has undefined behavior only if `y==0`. It's up to the programmer to ensure that, when the statement using that expression is reached, `y` is not 0. There are countless other examples like invalid array indices or pointers, signed overflow, etc.
R..
+21  A: 

I once had the dereference of a null pointer (which was being used to set a value) cause a vision system to whip its stepper motor around really fast, throwing parts inside the cabinet. It turned out that the stepper motor's control registers were mapped to the lowest memory addresses. That wasn't a smart choice.

-John

+3  A: 

#pragma directives are implementation defined. On old versions of GCC, unrecognized pragmas would launch Emacs running a towers of hanoi simulation, or a game of NetHack.

rlbond
I had to do some googling, completely ready to call you a liar, rlbond.
Shmoopty
To be precise, that happened when compiling, so the compiler would launch Nethack or whatever. It didn't continue compiling, as I remember.
David Thornley
+30  A: 

Since nobody's pointed out yet, the worst that can happen is probably that nothing goes wrong and you don't notice it. Then a hacker notices it and figures out how to inject arbitrary data into your system over the network, giving them full control at the privilege level of the process that is running. They wait until your system is holding some sufficiently important information (like credit card info) or controls some sufficiently important mechanism (eg a missile, or a power grid or an mri or 10 million desktops) and then come up with some lucrative way to screw over the people running those systems.

Accidents aren't malicious, so you have luck on your side and nothing too bad is likely to happen. Security is a different matter.

Jeremy Huiskamp
+1. Security flaws are the worst bugs, pretty much by definition of "security".
Steve Jessop
+2  A: 

It could open a security whole, see: Buffer overrun exploitation

hasen j
If a security whole in your software comes fourth, you half to fix it. :)
bk1e
@bk1e, lol! I don't want to fix the type now (too late), it will bring up an old question to the front page.
hasen j
+6  A: 

You don't want to risk it.

coppro
lol, that's a joke, right? "If you're looking for a way to defend your country, state, or military dictatorship, look no further. The solution is here. "
hasen j
Yes; the site is designed to make fun of the open-endedness of the definition of UB.
coppro
"The algorithm was simple; launch, count to 6 and then hit the nearest hot target. (oops)" :D
Tor Valamo
+1 for the excellent reference!
Alek
http://dialspace.dial.pipex.com/prod/dialspace/town/green/gfd34/art/ check your malloc return values...
Amigable Clark Kant
+4  A: 

I once accessed a double via a pointer to long long int, and right after that, the lotto ticket I bought didn't win.

What are the chances?

j_random_hacker
Isn't something almost identical (int to float, I believe) done in the infamous fast-inverse-square-root from Quake?
Chris Lutz
j_random_hacker
+2  A: 

I once installed a kernel driver of the wrong version, and it forced my PC into psychedelic agony. It was more fun than harm though.

Pavel Shved
+1  A: 

Okay, long after asking the question we encountered a nice example. The program would read outside the allocated buffer while preparing a packet for sending over the network.

If some memory it tried to read was not mapped into the program address space it would crash with access violation. Otherwise it would effectively send some unrelated data over the network, that data would be ignored by the recipient and both the program and the recipient would continue normally. Ironically the bug has been there for years and was not noticed until recently when the program changed from sending unrelated data to crashing.

That's so in the spirit of what user Jeremy Huiskamp answers in the accepted answer to this question. It's plain luck there was not a password or something really interesting in the memory region the program sent over the network.

sharptooth