Crashing: Easy to Do When You Don’t Want to, Hard When You Do

The challenge: in C or C++, come up with a way to crash your application, running as little code as possible. It should be a cross-platform solution that works with any compiler, on any system, with any CPU architecture.

The first way that comes to mind is, let’s dereference a null pointer and write to it!

int *a = 0x0;
(*a) = 0xDEADDEAD;

But this has a nasty problem with it — if the compiler doesn’t think the variable “a” is being used for anything, then it can optimize it away. So unless you trick the compiler into assuming “a” is important and can’t be elided, this trick won’t work. Thankfully, there is a way to do this: make the variable volatile!

volatile int *a = 0x0;
(*a) = 0xDEADEAD;

But there’s problems with this too. For one, the specification says that dereferencing a null pointer is undefined behavior. It is a bit shaky as to whether that still applies to volatile pointers, but there’s a bigger issue. It is possible for that operation to work. Nothing says you cannot set the first page of memory to be read/write. You can alter the protection flags of the __PAGEZERO segment in a Mach-O binary such that the first page is read/write/execute. So I would say that this approach isn’t reliable.

Wait a second… what about a standardized way to crash: the abort function. According to the specification, abort “causes abnormal program termination to occur…”, which sounds like it fits the bill for us!

abort();

Unfortunately, there are a few caveats here as well. One is that abort functions by raising the SIGABRT signal, and the specification says if that signal is being caught and doesn’t return, the abort doesn’t execute. Also, in the Win32 implementation of abort, it ends up calling the ExitProcess function, which can run further code such as DllMain in shared libraries. So this doesn’t actually “crash” immediately and it can potentially be ignored.

Okay, so it abort doesn’t fit the bill, and null pointer dereferencing may or may not work, maybe there’s another way to crash. What about a good old-fashioned stack overflow?

struct kaboom {
	kaboom() { struct kaboom k; }
} kersplat;

This entertaining code defines a structure with a constructor, and the constructor defines another instance of itself. This should continue on ad nauseum until the process runs out of stack space and crashes.

Unfortunately, this doesn’t meet our needs either! For starters, who says that the stack can be exhausted? You could be on hardware where the stack is enormous and this code would take an incredible amount of time to overflow the stack. Beyond that, because this code does take time to execute, there can be thread context switches. So further code can be executed while our code is attempting to bring the process down.

Perhaps we need to get more creative. Let’s install a “death landing pad” in our program’s main function, and use setjmp/longjmp to ensure that no matter what’s happening in our application, we can terminate.

#include <setjmp.h>

jmp_buf death;

void kill( void )
{
	longjmp( death, 1 );
}

int main( void )
{
	if (0 != setjmp( death )) {
		return -1;
	}
	kill();

	return 0;
}

When this code runs, setjmp is called the first time to set up the death jump buffer. Then kill is called, and it longjmps back to where setjmp was called, and returns the value 1. This causes the if clause to be entered and we leave main, which terminates the application.

Except this fires even more code than abort on Windows does! Leaving main will call atexit handlers, and cleanly unload shared libraries (calling DllMain), etc. Also, it’s not a crash — the code works! But what if we got rid of the setjmp and made longjmp jump off to a non-existent environment?

#include <setjmp.h>

jmp_buf death;

void kill( void )
{
	longjmp( death, 1 );
}

int main( void )
{
	kill();

	return 0;
}

Unfortunately, this is undefined behavior according to the C99 specification. So that means it’s not guaranteed to crash. It could simply noop, it could jump somewhere valid, we just don’t know.

At this point, I should probably mention that I’ve set ourselves up for failure. If we’re trying to find a standards-compliant way to crash an application immediately, there isn’t one. Search the C99 or C++11 specifications for the term “crash” and you’ll find it’s not mentioned once. There is no reliable way to cause your application to crash according to my requirements. This is one of those incredibly funny contradictions (at least, it’s funny to me) that you run across in programming. Ask any programmer how to crash their application, and you can get dozens of answers back without having to put any thought into it. Yet none of those answers are guaranteed to crash in all instances, on all platforms because the behavior is simply undefined. Which brings me to the moral of my story: the converse of the previous sentence is also true. When dealing with undefined behaviors, just because it works on one platform does not mean it will work on another. Undefined means undefined.

tl;dr: it’s impossible to crash! Reliably. Seriously.

This entry was posted in C/C++ and tagged , . Bookmark the permalink.

4 Responses to Crashing: Easy to Do When You Don’t Want to, Hard When You Do

  1. Rajendra says:

    Lovely article! Liked it a lot! Thanks.

  2. Dan says:

    Aaron,

    Just saw this recent question on StackOverflow: “What is the easiest way to make a C++ program crash?”

    (URL is: http://stackoverflow.com/questions/8481783/what-is-the-easiest-way-to-make-a-c-program-crash)

    The variety of answers, and the flurry of comments under most of them, proves your point. Most people seem to settle on abort() (or some way of reaching abort(), such as through assert() ) – but as you pointed out, even that isn’t a sure-fire approach.

  3. Dan says:

    I’m baaacckkk….. :-)

    A newer post on reddit & Hacker News (“The Shortest Crashing C Program”) is interesting, if only due to the comments from people who’ve come up with clever ways to torture the compiler.

    http://www.reddit.com/r/programming/comments/1ez1ce/the_shortest_crashing_c_program/

  4. Aaron Ballman says:

    Hey Dan, welcome back! :-D Yeah, I saw that this morning and it made me laugh. That’s been a pretty well-known thing in the compiler world since C lets you create applications that are freestanding. You can do the same thing with less characters by supplying the proper flags for it! Try an empty file with -ffreestanding. :-)

Leave a Reply

Your email address will not be published.