{"id":24,"date":"2002-08-15T21:57:48","date_gmt":"2002-08-15T11:57:48","guid":{"rendered":"http:\/\/www.thunderguy.com\/plusplus\/20050421\/visual-c-exception-handling\/"},"modified":"2006-09-05T10:44:58","modified_gmt":"2006-09-05T00:44:58","slug":"visual-c-exception-handling","status":"publish","type":"post","link":"https:\/\/thunderguy.com\/semicolon\/2002\/08\/15\/visual-c-exception-handling\/","title":{"rendered":"Visual C++ exception handling"},"content":{"rendered":"<p class=\"abstract\">This article describes a problem with the default handling of exceptions in Microsoft&#8217;s Visual C++ compilers. The problem is caused by the compiler&#8217;s extension to the C++ exception handling mechanism. I then give a technique that properly exploits this extension, bringing it into line with normal C++ exception handling. This allows programs to deal with exceptions that are normally very difficult to handle, such as memory access violations.<\/p>\n<p>This article was originally based on Visual C++ 6, and the same issues exist in the Visual Studio .NET C++ compiler. Finally, after at least six years, Microsoft fixed the fundamental problem in Visual C++ 2005. But to fully take advantage of this, it&#8217;s still necessary to implement an exception translation scheme like the one described in this article.<\/p>\n<h2>Win32 hardware exceptions<\/h2>\n<p>Under Visual C++, certain exceptional runtime conditions can be treated something like C++ exceptions. These exceptions are raised by the OS for events like memory access violations, division by zero, and so on. A (presumably) full list is in Microsoft&#8217;s <a href=\"http:\/\/msdn.microsoft.com\/\">MSDN Library<\/a> under &#8220;EXCEPTION_RECORD&#8221;.<\/p>\n<p>They are referred to in the documentation as &#8220;hardware exceptions&#8221;, &#8220;C exceptions&#8221;, &#8220;structured exceptions&#8221; and &#8220;C structured exceptions&#8221;. Actually, they are neither C-specific nor structured (at least compared to C++ exceptions). I refer to them as &#8220;Win32 hardware exceptions&#8221; or just &#8220;Win32 exceptions&#8221; because they are specific to the Win32 operating systems and hardware on which they run.<\/p>\n<h2>Visual C++ programs may be unstable by default<\/h2>\n<p>Visual C++ is a good compiler. But, like all compilers, it has some bad features. The default handling of Win32 exceptions in pre-2005 versions is one of them.<\/p>\n<p><!--more-->In general, when a computer program program causes (say) a memory access violation, the program could either:<\/p>\n<ol>\n<li>continue in a consistent state;<\/li>\n<li>crash immediately; or<\/li>\n<li>continue in an inconsistent state, possibly misbehaving or even crashing later.<\/li>\n<\/ol>\n<p>The first option is clearly the best. If this is is not possible, the second option is acceptable (and usually easy to achieve), since it maximises chances of finding the bug. The second option is taken by Visual C++ 2005.<\/p>\n<p>Unfortunately, the default behaviour in a pre-2005 Visual C++ program is the third option. This behaviour makes it very difficult to find the bug that lead to the problem in the first place; the program may make it through testing and into production before the bug comes to light. A good, old-fashioned crash is much more obvious, and therefore easier to find and debug.<\/p>\n<p>Now, sometimes the third option may be acceptable. For example, if a program is required to use a third-party library, and the library has bugs of this kind, and the developers have no access to the library source code, then the first option may be ruled out, and it may be considered better for the program to limp along rather than die. In most cases though, we want to handle such errors gracefully and find the bug that causes them.<\/p>\n<h2>Default handling of Win32 exceptions may be dangerous<\/h2>\n<p>According to the default behaviour in pre-2005 Visual C++, when a Win32 exception occurs (possibly nested) in a <code>try{}<\/code> block that has a corresponding <code>catch(...)<\/code> block, the call stack is unwound and the catch block will be entered. (This in itself is strange behaviour: catch is meant to catch C++ exceptions only, so why anyone would expect it to catch an access violation or division by zero is beyond me.)<\/p>\n<p>However, the stack may not be unwound properly as it would if it were a normal C++ exception being caught; in particular, destructors of some stack-based objects may not be called. Furthermore, no information will be available about the Win32 exception. (Of course, this is always a problem with <code>catch(...)<\/code> blocks.)<\/p>\n<p>As a result, the program will now be in an unstable state, and there is no way to determine where the problem occurred that triggered the Win32 exception.<\/p>\n<p>This problem does not occur in Visual C++ 2005, where <code>catch(...)<\/code> never catches Win32 exceptions. This makes a big difference to program stability and consistency, but there is still a lot of room for improvement, as discussed below.<\/p>\n<p><strong>This is a breaking change in Visual C++ 2005.<\/strong> In pre-2005 Visual C++, <code>catch(...)<\/code> can catch Win32 exceptions. In Visual  C++ 2005, it never does. This change, which could break existing code, was introduced very quietly. Perhaps it&#8217;s an unintended (but welcome) side effect of the integration with .NET and Managed C++. We know it&#8217;s a breaking change because it breaks Microsoft&#8217;s own example code on their <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/de5awhsw.aspx\">Exception Handling Differences<\/a> page. We know it was introduced quietly because it is not listed on their <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/ms177253.aspx\">Breaking Changes in the Visual C++ 2005 Compiler<\/a> page.<\/p>\n<h2>Synchronous exception handling and <code>catch(...)<\/code><\/h2>\n<p>The source of this instability lies in the interaction of two aspects of the behaviour of default programs: the synchronous exception-handling model, and the use of <code>catch(...)<\/code>.<\/p>\n<p><strong>Synchronous exception handling is the default.<\/strong> The default <code>\/GX<\/code> option (<code>\/EHsc<\/code> in Visual C++ 2005) causes Visual C++ programs to be compiled with the &#8220;synchronous&#8221; exception-handling model, where the compiler assumes that exceptions can only be thrown with the throw statement (which is true in standard C++). This allows certain optimisations: for example, if the compiler can determine that nothing will be thrown inside a given try block, then it can avoid generating all the code to unwind the stack (e.g. call appropriate destructors) for the catch.<\/p>\n<p><strong><code>catch(...)<\/code> always catches Win32 exceptions.<\/strong> In pre-2005 Visual C++, a <code>catch(...)<\/code> block will by default be entered whenever a Win32 exception (e.g. divide by zero or memory access violation) occurs in its try block. This is not much use, because by the time the catch block is entered, no information about the error is available.<\/p>\n<p>Therefore, for any pre-2005 Visual C++ program that contains <code>catch(...)<\/code> and that was compiled with default settings, any line that (for example) dereferences a pointer can throw a catchable exception; but the compiler will optimise based on the assumption that it can&#8217;t.<\/p>\n<p>The second catch block in Listing 1 illustrates this.<\/p>\n<p class=\"caption top\">Listing 1: Demonstrating the problem<\/p>\n<pre class=\"code\">\r\n<code> 1  class whatever\r\n 2  {\r\n 3  public:\r\n 4      whatever(int i) : id(i) { std::cerr &lt;&lt; id &lt;&lt; \"-constructor \"; }\r\n 5      ~whatever(void) { std::cerr &lt;&lt; id &lt;&lt; \"-destructor \" ; }\r\n 6  private:\r\n 7      int id;\r\n 8  };\r\n 9  \r\n10  int reciprocal(int i) {\r\n11      return 1\/i;\r\n12  }\r\n13  \r\n14  int main() {\r\n15      int k = 0;\r\n16      std::cerr &lt;&lt; \"first-try \";\r\n17      try {\r\n18          whatever w1(1);\r\n19          int r = reciprocal(0);\r\n20      }\r\n21      catch (...) {\r\n22          std::cerr &lt;&lt; \"caught \";\r\n23      }\r\n24      std::cerr &lt;&lt; \"second-try \";\r\n25      try {\r\n26          whatever w2(2);\r\n27          int r = 1\/k;\r\n28      }\r\n29      catch (...) {\r\n30          std::cerr &lt;&lt; \"caught \";\r\n31      }\r\n32      std::cerr &lt;&lt; \"exiting \";\r\n33  }<\/code><\/pre>\n<p>Under Visual C++ 2005, this program behaves as you&#8217;d expect a program to behave on any platform: it prints &#8220;<code>first-try<\/code>&#8221; and then crashes.<\/p>\n<p>Under pre-2005 Visual C++, line 19 calls a function that throws a Win32 exception. As expected, <code>w1<\/code>&#8216;s destructor is called, and then the exception is caught at line 22. So far, so good.<\/p>\n<p>But at line 27 we have a direct divide by zero. This throws a Win32 exception as before, and the exception is caught at line 30, but <code>w2<\/code>&#8216;s destructor never gets called. This happens because the compiler has incorrectly assumed that the try block starting at line 25 will not throw any exceptions.<\/p>\n<p>The previous try block behaves differently. Since it contains a function call, the optimiser has assumed that it may throw, so has not optimised away the destructor call. But note that if this program is compiled with the \/O1 option to minimise code size, then neither destructor gets called.<\/p>\n<p>Note that this is arguably not a bug; that&#8217;s how the compiler is meant to behave when synchronous exception handling is enabled. As the Visual C++ documentation states:<\/p>\n<blockquote><p>\nCatching hardware exceptions is still possible with the synchronous model. However, some of the unwindable objects in the function where the exception occurs may not get unwound, if the compiler judges their lifetime tracking mechanics to be unnecessary for the synchronous model.\n<\/p><\/blockquote>\n<p>In other words, catching Win32 exceptions (and asynchronous exception handling in general) under the synchronous exception handling model is at the compiler&#8217;s discretion. Unsurprisingly, the compiler&#8217;s discretion depends on the optimisation level.<\/p>\n<h2>How optimisation affects exception handling<\/h2>\n<p>The following near-identical programs illustrate how the optimisation level in Visual C++ can have a profound effect on the behaviour of a program when a Win32 exception occurs.<\/p>\n<p class=\"caption top\">Listing 2<\/p>\n<pre class=\"code\">\r\n<code> 1  int main() {\r\n 2     try {\r\n 3\r\n 4        char* bad = 0;\r\n 5        *bad = 0; \/\/ Generates EXCEPTION_ACCESS_VIOLATION\r\n 6     }\r\n 7     catch(...) {\r\n 8        std::cerr &lt;&lt; \"catch\";\r\n 9     }\r\n10  }<\/code><\/pre>\n<p class=\"caption top\">Listing 3<\/p>\n<pre class=\"code\">\r\n<code> 1  int main() {\r\n 2     try {\r\n 3        std::cerr &lt;&lt; \"try \";\r\n 4        char* bad = 0;\r\n 5        *bad = 0; \/\/ Generates EXCEPTION_ACCESS_VIOLATION\r\n 6     }\r\n 7     catch(...) {\r\n 8        std::cerr &lt;&lt; \"catch\";\r\n 9     }\r\n10  }<\/code><\/pre>\n<p>Listing 2 and Listing 3 are identical except that Listing 2 prints some text at line 3. According to the C++ standard, both programs produce undefined behaviour. However, in general you could reasonably expect Listing 2 just to crash, and Listing 3 to print &#8220;<code>try<\/code>&#8221; and then crash. Using Visual C++ with default options, you may instead expect Listing 2 to print &#8220;<code>catch<\/code>&#8220;, and Listing 3 to print &#8220;<code>try catch<\/code>&#8220;, as the Win32 exception is caught.<\/p>\n<p>Actually, under pre-2005 Visual C++ with default options, the programs behave inconsistently.<\/p>\n<p>Listing 2 crashes, because the <code>catch(...)<\/code> has been ignored by the optimising compiler. (This depends on the compiler switches.)<\/p>\n<p>Listing 3, however, prints &#8220;<code>try catch<\/code>&#8221; as the <code>catch(...)<\/code> catches the access violation Win32 exception. (In fact, this occurs regardless of which compiler switches are used.)<\/p>\n<p>Visual C++ 2005 behaves consistently, since the <code>catch(...)<\/code> has no effect. Both programs simply crash.<\/p>\n<p><!--nextpage--><\/p>\n<h2>Solution overview<\/h2>\n<p>So the basic problem is this. In a pre-2005 Visual C++ program with default settings, Win32 exceptions can sometimes be caught with <code>catch(...)<\/code> and will sometimes fail to unwind the stack properly. Here I describe three solutions to this, each requiring different actions on the part of the programmer. They are:<\/p>\n<p><strong>1. Don&#8217;t catch Win32 exceptions.<\/strong> If you never catch Win32 exceptions, they will always cause the program to crash. This is perhaps the most obvious result, and is how most computer programs work. When a Win32 exception occurs, you will be able to use your normal debugging tools to isolate and correct the error that led to the exception.<\/p>\n<p><strong>2. Ensure the stack is unwound correctly when catching Win32 exceptions.<\/strong> This approach ensures that Win32 exceptions are always caught by <code>catch(...)<\/code> and will unwind the stack properly when caught. The disadvantage here is that no information about the exception is available at the point where it is caught.<\/p>\n<p><strong>3. Turn Win32 exceptions into C++ exceptions.<\/strong> This approach fully integrates Win32 exceptions into the normal C++ exception handling mechanism. When a Win32 exception occurs, it is automatically turned into a rich C++ exception object and handled according to the normal C++ exception rules. This is perhaps the most elegant approach, but it requires the most work on the part of the programmer.<\/p>\n<h2>Solution 1: Don&#8217;t catch Win32 exceptions<\/h2>\n<p>If you never catch Win32 exceptions, they will always cause the program to crash. This is perhaps the most obvious result, and is how most computer programs work. In Visual C++ 2005, you can&#8217;t catch Win32 exceptions directly, so there&#8217;s no problem. However, in pre-2005 Visual C++, you must avoid using <code>catch(...)<\/code> anywhere.<\/p>\n<p>The problem with this is, of course, that <code>catch(...)<\/code> can be quite useful. Even when the developer knows which types of exception can be thrown, and therefore writes:<\/p>\n<pre class=\"code\">\r\n<code>catch (exceptionBase&amp;) {\r\n    \/\/ clean up\r\n    throw;\r\n}<\/code>\r\n<\/pre>\n<p>It may better express the programmer&#8217;s intention to write this instead:<\/p>\n<pre class=\"code\">\r\n<code>catch (...) {\r\n    \/\/ clean up\r\n    throw;\r\n}<\/code>\r\n<\/pre>\n<p>In other words, &#8220;if any exception occurs, clean up and rethrow it&#8221;. It&#8217;s a shame to have to avoid this.<\/p>\n<h2>Solution 2: Ensure the stack is unwound correctly<\/h2>\n<p>In pre-2005 Visual C++, it is possible to ensure that Win32 exceptions are always caught by <code>catch(...)<\/code> and will unwind the stack properly. However, no information about the exception will be available. This happens if you compile with the &#8220;asynchronous&#8221; exception-handling model.<\/p>\n<p>In the asynchronous exception-handling model, the compiler assumes that any code can cause an exception. This is actually (more-or-less) true of any pre-2005 Visual C++ code that has a <code>catch(...)<\/code> handler, since <code>catch(...)<\/code> always catches Win32 exceptions.<\/p>\n<p>To enable the asynchronous exception-handling model, compile with the <code>\/EHa<\/code> compiler switch.<\/p>\n<p class=\"caption top\">Listing 4: Unwinding the stack<\/p>\n<pre class=\"code\">\r\n<code> 1  class thing\r\n 2  {\r\n 3  public:\r\n 4      thing() { std::cerr &lt;&lt; \"hello \"  ; }\r\n 5      ~thing() { std::cerr &lt;&lt; \"goodbye \"; }\r\n 6  };\r\n 7  \r\n 8  int main() {\r\n 9      try {\r\n10          std::cerr &lt;&lt; \"try \";\r\n11          thing t1;\r\n12          char* cp = 0;\r\n13          *cp = 'a';\r\n14      }\r\n15      catch (...) {\r\n16          std::cerr &lt;&lt; \"catch\";\r\n17      }\r\n18  }<\/code><\/pre>\n<p>In Visual C++ 2005, this simply prints &#8220;<code>try hello<\/code>&#8221; and then crashes. Nice and simple.<\/p>\n<p>Compiled with the default <code>\/GX<\/code> switch on pre-2005 Visual C++, Listing 4 outputs &#8220;<code>try hello catch<\/code>&#8220;. It fails to unwind the stack correctly; the <code>t1<\/code> object destructor does not get called. If you compile with <code>\/EHa<\/code>, the stack will unwind properly and you get &#8220;<code>try hello goodbye catch<\/code>&#8221; as expected.<\/p>\n<p>Therefore, if a pre-2005 Visual C++ program contains <code>catch(...)<\/code>, then it should be compiled with asynchronous exception handling enabled (<code>\/EHa<\/code>). Otherwise, if the <code>catch(...)<\/code> catches a Win32 exception, &#8220;some of the unwindable objects in the function where the exception occurs may not get unwound&#8221; (Visual C++ Programmer&#8217;s Guide), which could lead to resource leaks or worse.<\/p>\n<p>Note that this approach requires the compiler to insert complete cleanup code in every try block, even if it could normally determine that no C++ exception can be thrown from within it. This may increase overall code size.<\/p>\n<h2>Solution 3: Turn Win32 exceptions into C++ exceptions<\/h2>\n<p>Perhaps the best solution, especially in a large program, is to transform Win32 exceptions into C++ objects that can be handled according to the normal C++ exception rules. This approach works equally well, and is equally useful, on Visual C++ 2005 and on earlier versions.<\/p>\n<p>To get this behaviour, you must create your own class and write an exception handler to &#8220;catch&#8221; Win32 exceptions and throw C++ exceptions. You must also compile with the <code>\/EHa<\/code> compiler option to enable asynchronous exception handling. At runtime, you install your handler by calling the global function <code>_set_se_translator()<\/code>.<\/p>\n<p>Background information on <code>_set_se_translator()<\/code> is available in Microsoft&#8217;s MSDN Library. There&#8217;s also a bare-bones example of this approach to exception handling.<\/p>\n<p>The nice thing about this scheme is that the C++ exception object created can contain quite thorough information. For example, it could contain the kind of exception (divide by zero, access violation, etc.), the address at which the exception occurred, and even a stack trace.<\/p>\n<p>So here is the sequence of events when a Win32 exception occurs in a program using this scheme.<\/p>\n<ol>\n<li>The program installs its Win32 exception handler.<\/li>\n<li>The program runs for a while.<\/li>\n<li>At a crucial, deeply-nested point in the program, an access violation occurs.<\/li>\n<li>The Win32 exception handler is called, with details of the exception.<\/li>\n<li>The Win32 exception handler creates a new C++ object, initialising it with detailed information about the exception.<\/li>\n<li>The Win32 exception handler throws the C++ object as a C++ exception.<\/li>\n<li>The call stack unwinds to the nearest catch block for the C++ exception type. All destructors are called correctly, and in general everything is cleaned up as expected.<\/li>\n<li>The catch block has access to full information about the Win32 exception, though the C++ exception. It writes a log message for the programmers, whose debugging task is now much easier.<\/li>\n<\/ol>\n<p><!--nextpage--><\/p>\n<h2>Example: Turning Win32 exceptions into C++ exceptions<\/h2>\n<p>Here a sample implementation of a win32_exception class hierarchy. First, the header file for the exception classes:<\/p>\n<p class=\"caption top\">Listing 5: <code>win32_exception.h<\/code><\/p>\n<pre class=\"code\">\r\n<code>#include \"windows.h\"\r\n#include &lt;exception&gt;\r\n\r\nclass win32_exception: public std::exception\r\n{\r\npublic:\r\n    typedef const void* Address; \/\/ OK on Win32 platform\r\n\r\n    static void install_handler();\r\n    virtual const char* what() const { return mWhat; };\r\n    Address where() const { return mWhere; };\r\n    unsigned code() const { return mCode; };\r\nprotected:\r\n    win32_exception(const EXCEPTION_RECORD&amp; info);\r\n    static void translate(unsigned code, EXCEPTION_POINTERS* info);\r\nprivate:\r\n    const char* mWhat;\r\n    Address mWhere;\r\n    unsigned mCode;\r\n};\r\n\r\nclass access_violation: public win32_exception\r\n{\r\npublic:\r\n    bool isWrite() const { return mIsWrite; };\r\n    Address badAddress() const { return mBadAddress; };\r\nprivate:\r\n    bool mIsWrite;\r\n    Address mBadAddress;\r\n    access_violation(const EXCEPTION_RECORD&amp; info);\r\n    friend void win32_exception::translate(unsigned code, EXCEPTION_POINTERS* info);\r\n};<\/code>\r\n<\/pre>\n<p>A few notes on these classes:<\/p>\n<ul>\n<li>The basic class is <code>win32_exception<\/code>. To set up the enhanced exception handling in a thread, you should call <code>win32_exception::install_handler()<\/code>. This must be done in <em>each<\/em> thread for which you need the enhanced exception handling.<\/li>\n<li>Since access violations represent a common program bug, and since such exceptions have more information available (the type and location of the bad memory access), there is a specialised derived class for this case only.<\/li>\n<li>The <code>win32_exception<\/code> class inherits from the standard library exception classes for consistency. However, even though access violations and divisions by zero could legitimately inherit from <code>std::logic_error<\/code>, this is not the case in general for Win32 exceptions. Therefore, <code>win32_exception<\/code> inherits from <code>std::exception<\/code> only.<\/li>\n<li>The constructors are private, since only <code>win32_exception::translate()<\/code> is allowed to instantiate these exceptions.<\/li>\n<li>The two classes are tightly coupled (note that the base class&#8217;s <code>win32_exception::translate()<\/code> is a friend of the derived class <code>access_violation<\/code>). This is fine in this lean implementation, but if you wanted to create a large hierarchy of separate classes for each kind of Win32 exception, you&#8217;d want to change this design.<\/li>\n<\/ul>\n<p>Now here&#8217;s the implementation of these classes:<\/p>\n<p class=\"caption top\">Listing 6: <code>win32_exception.cpp<\/code><\/p>\n<pre class=\"code\">\r\n<code>#include \"win32_exception.h\"\r\n#include \"eh.h\"\r\n\r\nvoid win32_exception::install_handler()\r\n{\r\n    _set_se_translator(win32_exception::translate);\r\n}\r\n\r\nvoid win32_exception::translate(unsigned code, EXCEPTION_POINTERS* info)\r\n{\r\n    \/\/ Windows guarantees that *(info-&gt;ExceptionRecord) is valid\r\n    switch (code) {\r\n    case EXCEPTION_ACCESS_VIOLATION:\r\n        throw access_violation(*(info-&gt;ExceptionRecord));\r\n        break;\r\n    default:\r\n        throw win32_exception(*(info-&gt;ExceptionRecord));\r\n    }\r\n}\r\n\r\nwin32_exception::win32_exception(const EXCEPTION_RECORD&amp; info)\r\n: mWhat(\"Win32 exception\"), mWhere(info.ExceptionAddress), mCode(info.ExceptionCode)\r\n{\r\n    switch (info.ExceptionCode) {\r\n    case EXCEPTION_ACCESS_VIOLATION:\r\n        mWhat = \"Access violation\";\r\n        break;\r\n    case EXCEPTION_FLT_DIVIDE_BY_ZERO:\r\n    case EXCEPTION_INT_DIVIDE_BY_ZERO:\r\n        mWhat = \"Division by zero\";\r\n        break;\r\n    }\r\n}\r\n\r\naccess_violation::access_violation(const EXCEPTION_RECORD&amp; info)\r\n: win32_exception(info), mIsWrite(false), mBadAddress(0)\r\n{\r\n    mIsWrite = info.ExceptionInformation[0] == 1;\r\n    mBadAddress = reinterpret_cast&lt;win32_exception::Address&gt;(info.ExceptionInformation[1]);\r\n}<\/code>\r\n<\/pre>\n<p class=\"note\">For more details on <code>EXCEPTION_RECORD<\/code> and the suspicious-looking cast in the <code>access_violation<\/code> constructor, look up EXCEPTION_RECORD in the MSDN Library.<\/p>\n<p>And finally, here&#8217;s part of a program that uses these classes:<\/p>\n<p class=\"caption top\">Listing 7: <code>main.cpp<\/code><\/p>\n<pre class=\"code\">\r\n<code>#include \"win32_exception.h\"\r\n#include &lt;iostream&gt;\r\n\r\nint main() {\r\n    win32_exception::install_handler();\r\n    try {\r\n        DoComplexAndErrorProneThings();\r\n    }\r\n    catch (const access_violation&amp; e) {\r\n        std::cerr &lt;&lt; e.what() &lt;&lt; \" at \" &lt;&lt; std::hex &lt;&lt; e.where()\r\n            &lt;&lt; \": Bad \" &lt;&lt; (e.isWrite()?\"write\":\"read\")\r\n            &lt;&lt; \" on \" &lt;&lt; e.badAddress() &lt;&lt; std::endl;\r\n    }\r\n    catch (const win32_exception&amp; e) {\r\n        std::cerr &lt;&lt; e.what() &lt;&lt; \" (code \" &lt;&lt; std::hex &lt;&lt; e.code()\r\n            &lt;&lt; \") at \" &lt;&lt; e.where() &lt;&lt; std::endl;\r\n    }\r\n}<\/code>\r\n<\/pre>\n<p>If <code>DoComplexAndErrorProneThings()<\/code> attempts to write through a null pointer, a win32_exception will be thrown and something like the following will appear.<\/p>\n<p><code>Access violation at 72a5ee00: Bad write on 00000000<\/code><\/p>\n<p>The great thing about this is that the call stack unwinds correctly as the exception is being thrown: local objects are destroyed, resources are released, and log messages can be written, just as if a normal C++ exception had been thrown &#8212; because it has!<\/p>\n<p>The EXCEPTION_POINTERS structure that gets passed to <code>win32_exception::translate()<\/code> contains a lot of other information. In particular, you can use it to get a stack trace, which would be useful for debugging. This would complicate the exception classes a bit, so I haven&#8217;t done it here.<\/p>\n<h2>Summary<\/h2>\n<p>Visual C++ treats certain runtime errors such as access violations in a similar way to regular C++ exceptions. Unfortunately, the default compiler and project settings in pre-2005 versions cause this to happen in a half-baked way, leading to unstable programs. Visual C++ 2005 treats such errors in a more predictable way: by crashing your program.<\/p>\n<p>However, by writing a small amount of extra code, such errors can be handled exactly the same way as C++ exceptions. This greatly aids tracking down mysterious crashes, and allows programs to recover from bugs that normally would prove fatal.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article describes a problem with the default handling of exceptions in Microsoft&#8217;s Visual C++ compilers. The problem is caused by the compiler&#8217;s extension to the C++ exception handling mechanism. I then give a technique that properly exploits this extension, bringing it into line with normal C++ exception handling. This allows programs to deal with [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[3],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","tag-cpp"],"_links":{"self":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":0,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"wp:attachment":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}