Freigeben über


Global crash handler for c++ application

I am working on designing Maintainability & Supportability features for my product. I faced a scenario where it requires implementing global exception handler at the process level for c++ component. The component will be installed at end-user's desktop and is prone to un-known errors and exception which are usually not encountered during development and testing phases. There are logging mechanism available to write function call flow into .log file but application crashing is not acceptable at all. Our development team will require data patterns for analyzing the root cause of the crash in order to fix them. Having said all these, (1) the code-base for our product is 2 to 3 years old, handled by other team(s) and our team is new to it (2) There is no structured exception handling implemented. Following are the challenges: We need to clean-up code and implement exception handling mechanism; but this is hugely time consuming. We are heading towards release dates and are implementing feature to the product. Hence, not possible with-in the time lines available to do entire code clean-up.

 Now am analyzing a way to implement a global exception handler at process-level of our multi threaded application. By this way, I will have a place to handle any unhandled exception thrown by the application at first-chance. Upon handling first-chance exception, I can create mini dump of the process and allow process to gracefully exit. I found following APIs to do this job.

_set_se_translator

Handles Win32 exceptions (C structured exceptions) as C++ typed exceptions.

_se_translator_function _set_se_translator(

            _se_translator_function seTransFunction

);

Good point is - In a multithreaded environment, translator functions are maintained separately for each thread. Each new thread needs to install its own translator function. Thus, each thread is in charge of its own translation handling. _set_se_translator is specific to one thread; another DLL can install a different translation function.

Worse part is - You must use /EHa when using _set_se_translator. This involves security issues and it is not good practice to compile with this switch.

SetUnhandledExceptionFilter

Enables an application to supersede the top-level exception handler of each thread and process.

LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(

LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter

);

After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.

Let us look at how OS processes unhandled exception is as follows:

When an exception occurs (with Windows XP SP>=2, Windows 2003, and Windows Vista), the usual way the OS processes the exception is - pass control to the per-process Vectored Exception Handlers, if any. If the exception is not processed, pass the control to the per-thread top SEH handler. SEH are chained and called in turn if the exception is not processed by the previous in the chain. If the exception has not been processed by any of the previous handlers, the final SEH handler (set by the system), will call kernel32!UnhandledExceptionFilter. This function will decide what it should do depending if the process is debugged or not. If it is not debugged, it will call the user-defined filter function (set via kernel32!SetUnhandledExceptionFilter). If it debugged, the program will be terminated.

Caution needed while using SetUnhandledExceptionFilter method:

Don’t trust unhandled exception filters, as the model is brittle and easily breaks in processes that load and unload dlls frequently. If you must register an unhandled exception filter, do it in a dll that is never unloaded (or even the main .exe) to prevent the unhandled exception filter from being used as an attack vector. Don’t try to call the previous unhandled exception filter pointer that you get back from SetUnhandledExceptionFilter, as this introduces a security risk. Don’t install an unhandled exception filter from within a plugin type dll that is loaded in a third party application, and especially don’t install an unhandled exception filter in a plugin type dll that gets unloaded on the fly.

I used SetUnhandledExceptionFilter method and delegated exception handler to it. Inside this exception handler function, created a user-mode process dump using MiniDumpWriteDump() method and saved the .dmp file into the application's log files directory. There is a 'troubleshoot' screen which has 'Send Log' button. Upon click of this button, with explicit permission from end-user; I compress my application specific log files and this dump file and upload to server. By this, our dev team will get complete snapshot of the state of the process when crashed.

 

In my opinion, using structured exception handling is the highly suggested and avoid using global crash handler.

 

References:

 

SetUnhandledExceptionFilter:

https://msdn2.microsoft.com/en-us/library/ms680634.aspx

_set_se_translator:

https://msdn2.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx

Structured Exception Handling:

https://msdn2.microsoft.com/en-us/library/ms680657(VS.85).aspx

Crash course on Win32 SEH:

https://www.microsoft.com/msj/0197/exception/exception.aspx

MiniDumpWriteDump:

https://msdn2.microsoft.com/en-us/library/ms680360(VS.85).aspx