04 September 2011

Crash Protection

Crash Protection from RuntimeCompiledC++ on Vimeo.

We felt that for RCC++ to be really practical, it had to have a form of crash protection. After all, it would be a frustrating experience if you could avoid quitting, recompiling, reloading only until your first simple mistake, when a null pointer forces you to close it all down and start over.

We looked at two main approaches to achieving this - using a separate process and structured exception handling.

Google Chrome uses the process approach for each of its tabs, allowing one to crash without affecting any of the others. This is a very robust approach, but unless your engine's architecture has this in mind, it may result in a very large number of interprocess function calls which would have severe performance impact. We wanted an approach that would be easy to drop into existing projects.

Structured exception handling (SEH) is a Win32 API feature which allows handling of runtime errors such as access violations. It behaves much like standard exceptions but is in fact quite separate - there are various reasons why standard exceptions are not used on games consoles, but these don't affect SEH. When a runtime error such as a null pointer dereference occurs, the OS checks a stack of possible handlers registered by the application to see how to proceed. The crash dialogs you see in Windows are in fact the default handler; when Visual Studio's debugger is attached, that adds another.

Using SEH it is quite easy to catch an error and carry straight on. In our case, the key place for this is around the update calls on our game objects. When an update fails, we disable it until the code has been runtime-recompiled, when we try again. As you can see in the video, the rest of the application - rendering, GUI, logging - all keep running in the meantime.

But actually, you don't want to handle a crash silently - you'd really like to find out what caused it first! You could add code to produce a stack trace. However, debuggers like that in Visual Studio already provide a really ideal interface when crashes occur, allowing you to inspect state easily. So really, we would like to crash, but then continue.

In fact, this is exactly what we do - we first allow the crash to proceed as normal so we can use Visual Studio to debug it, after which the user can hit the "continue" button in the IDE. Usually this is quite useless but in our case we catch the crash on the second attempt - and proceed with execution. We get the best of both.

Without crash protection, rapid changes to live C++ might just let you shoot yourself in the foot faster. But now this isn't a fatal injury, you might as well select full automatic.