Analyzing a 0xE06D7363 exception

Print Friendly, PDF & Email

Sometimes it happens we have to analyze dumps of our application: it’s a mixed .NET/C/C++ software, so the legacy libraries can trigger unhandled exceptions that cause the process to crash.

In most of these cases either through the internal minidumper or thanks to the WER, the user is able to send us the core dump, that we analyze with WinDbg.

In a couple of cases the exception code resulted to be 0xE06D7363, which is a generic C++ error code that doesn’t provide any details.

Meaning of the error code

Looking at VS header files, we can find in ehdata.h that EH_EXCEPTION_NUMBER is defined as follows:

#define EH_EXCEPTION_NUMBER ('msc' | 0xE0000000) // The NT Exception # that we use

Which might seem a bit weird definition but once we realize that 'm' ==> 6D, 's' ==> 73 and 'c' ==> 63 (see the ASCII table), we get that 'msc' ==> 6D7363 and the OR with 0xE0000000 (the E stands for “exception“) will produce the final value 0xE06D7363.

First look at the Exception Context

Let’s start from the dump and see the last exception record:

0:000> .exr -1
ExceptionAddress: 00007ff876693b19 (KERNELBASE!RaiseException+0x0000000000000069)
   ExceptionCode: e06d7363 (C++ EH exception)
  ExceptionFlags: 00000001
NumberParameters: 4
   Parameter[0]: 0000000019930520 ==> magic number
   Parameter[1]: 00000045355fce90 ==> pointer to exception object
   Parameter[2]: 00007ff802eef9f0 ==> pointer to throw info
   Parameter[3]: 00007ff802d60000 ==> HINSTANCE of the DLL

this is where we get to know the exception number. As usual the next step is to check the stack:

0:000> k
  *** Stack trace for last set context - .thread/.cxr resets it
 # Child-SP          RetAddr               Call Site
00 00000045`355fcd10 00007ff8`737eeed3     KERNELBASE!RaiseException+0x69
01 00000045`355fcdf0 00007ff8`02e1646c     msvcr120!_CxxThrowException+0xb3 [f:\dd\vctools\crt\crtw32\eh\throw.cpp @ 154] 
02 ...
03 ...
04 ...

In this case the whole stack was available and we could actually get a lot of information right from it: the analysis could proceed and we found the culprit of the problem. Anyway, being able to get a more detailed information from the C++ runtime can help in trickier situations.

We start from the NT Exception Record definition (ehdata.h):

/////////////////////////////////////////////////////////////////////////////
//
// The NT Exception record that we use to pass information from the throw to
// the possible catches.
//
// The constants in the comments are the values we expect.
// This is based on the definition of EXCEPTION_RECORD in winnt.h.
//
[...]
typedef struct EHExceptionRecord {
   DWORD ExceptionCode;                        // The code of this exception. (= EH_EXCEPTION_NUMBER)
   DWORD ExceptionFlags;                       // Flags determined by NT
   struct _EXCEPTION_RECORD *ExceptionRecord;  // An extra exception record (not used)
   void * ExceptionAddress;                    // Address at which exception occurred
   DWORD NumberParameters;                     // Number of extended parameters. (= EH_EXCEPTION_PARAMETERS)
   struct EHParameters {
      DWORD magicNumber;                       // = EH_MAGIC_NUMBER1
      void * pExceptionObject;                 // Pointer to the actual object thrown
      ThrowInfo * pThrowInfo;                  // Description of thrown object
#if _EH_RELATIVE_OFFSETS
      void * pThrowImageBase;                  // Image base of thrown object
#endif
   } params;
} EHExceptionRecord;

Now it’s a bit clearer from whence the .exr -1 info are retrieved; let’s take a look at the #1 frame:

0:000> .frame 0n1;dv /t /v
01 00000045`355fcdf0 00007ff8`02e1646c     msvcr120!_CxxThrowException+0xb3 [f:\dd\vctools\crt\crtw32\eh\throw.cpp @ 154] 
@rdi              void * pExceptionObject = 0x00000045`355fce90
<unavailable>     struct _s__ThrowInfo * pThrowInfo = <value unavailable>
00000045`355fce10 struct EHExceptionRecord ThisException = struct EHExceptionRecord
@rbx              struct _s_ThrowInfo * pTI = 0x00007ff8`02eef9f0
00000045`355fce60 void * ThrowImageBase = 0x00007ff8`02d60000
<unavailable>     struct WinRTExceptionInfo ** ppWei = <value unavailable>
<unavailable>     unsigned int64 * exceptionInfoPointer = <value unavailable>
00007ff8`73839840 struct EHExceptionRecord ExceptionTemplate = struct EHExceptionRecord

We can identify here the two parameters passed in to the call to _CxxThrowException, that is:

definition of the _CxxThrowException (single underscore rod non-ARM)

pExceptionObject → 0x00000045`355fce90
pThrowInfo → <unavailable>

Starting from pExceptionObject we can navigate further and get the same values shown in the .exr -1 call:

0:000> dx -r1 (*((msvcr120!EHExceptionRecord *)0x45355fce10))
(*((msvcr120!EHExceptionRecord *)0x45355fce10))                 [Type: EHExceptionRecord]
    [+0x000] ExceptionCode    : 0xe06d7363 [Type: unsigned long]
    [+0x004] ExceptionFlags   : 0x1 [Type: unsigned long]
    [+0x008] ExceptionRecord  : 0x0 [Type: _EXCEPTION_RECORD *]
    [+0x010] ExceptionAddress : 0x0 [Type: void *]
    [+0x018] NumberParameters : 0x4 [Type: unsigned long]
    [+0x020] params           [Type: EHExceptionRecord::EHParameters]
    
0:000> dx -r1 (*((msvcr120!EHExceptionRecord::EHParameters *)0x45355fce30))
(*((msvcr120!EHExceptionRecord::EHParameters *)0x45355fce30))                 [Type: EHExceptionRecord::EHParameters]
    [+0x000] magicNumber      : 0x19930520 [Type: unsigned long]
    [+0x008] pExceptionObject : 0x45355fce90 [Type: void *]
    [+0x010] pThrowInfo       : 0x7ff802eef9f0 [Type: _s_ThrowInfo *]
    [+0x018] pThrowImageBase  : 0x7ff802d60000 [Type: void *]
  • Exception Code: 0xe06d7363
  • Flags: 1
  • Parameters: 4
    • Magic number: 0x19930520
    • Pointer to Exception Object: 0x45355fce90
    • Pointer to ThrowInfo: 0x7ff802eef9f0
    • HINSTANCE of the DDL that threw the exception: 0x7ff802d60000

The magic number is an internal value, defined in ehdata.h as follows

It’s useful to see how the ThrowInfo is defined:

ThrowInfo

Navigating the Exception Record

Given all the above, to get the object involved in the exception, we have to do some jumps starting from the pointer of the ThrowInfo; note that 0x00007ff802eef9f0 is the value of Parameter[2] we got right from the very first .exr -1 command we did:

0:000> dd 7ff802eef9f0
00007ff8`02eef9f0  00000000 000919c0 00000000 0018fa10  <== we'll use "0018fa10"
00007ff8`02eefa00  00000000 00000000 00000000 00000000
00007ff8`02eefa10  00000001 0018f940 00000000 00000000
00007ff8`02eefa20  00000002 0018fa38 0018f9a0 00000000
00007ff8`02eefa30  00000000 00000000 00000010 001ed9f8
00007ff8`02eefa40  00000000 ffffffff 00000000 00000018
00007ff8`02eefa50  000251e0 00000000 00000000 00000000
00007ff8`02eefa60  00000000 00000000 00000000 0018fac8

we can find here the fields of the ThrowInfo struct definition above, that is:

0:000> dx -r1 ((msvcr120!_s_ThrowInfo *)0x7ff802eef9f0)
((msvcr120!_s_ThrowInfo *)0x7ff802eef9f0)                 : 0x7ff802eef9f0 [Type: _s_ThrowInfo *]
    [+0x000] attributes       : 0x0 [Type: unsigned int]
    [+0x004] pmfnUnwind       : 596416 [Type: int]  =====> 0x000919c0
    [+0x008] pForwardCompat   : 0 [Type: int] 
    [+0x00c] pCatchableTypeArray : 1636880 [Type: int] ==> 0x0018fa10

We use the HINSTANCE to displace the pointer to pCatchableTypeArray (of type CatchableType):

// Step (1) 0x00007ff802d60000 + 0x0018fa10 = 0x00007FF802EEFA10
0:000> dd 0x00007FF802EEFA10
00007ff8`02eefa10  00000001 0018f940 00000000 00000000  // <== we'll use 0018f940

// Step (2) 0x00007ff802d60000 + 0x0018f940 = 0x00007FF802EEF940
0:000> dd 0x00007FF802EEF940
00007ff8`02eef940  00000000 001ef8e8 00000000 ffffffff  // <== we'll use 001ef8e8
CatchableTypeArray

Step (1): in the CatchableTypeArray the first integer is the number of items (0x00000001 in this case); 0x0018f940 is the address of the array of CatchableType.

Let’s take a look at the definition of a CatchableType:

CatchableType

Using these details we can better understand the:
Step (2): we use the address of the array we’ve found (0x0018f940) and we displace by the usual HINSTANCE, getting:
00000000 properties
0x00000000’001ef8e8 pointer to the TypeDescriptor, which definition is:

TypeDescriptor

what we’ll do next -Step (3)- is to use the TypeDescriptor pointer and jump forward by two pointers (0x10 – we skip pVFTable and spare) to go to the decorated name of the exception type; we’ll display it by using the WinDbg “da” command:

// Step(3): 0x00007ff802d60000 + 0x001ef8e8 + 0x10 = 0x00007FF802F4F8F8
0:000> da 0x00007FF802F4F8F8
00007ff8`02f4f8f8  ".?AVbad_alloc@std@@" ===> here's the decorated name of the actual exception!

In this dump the exception was not a bad allocation (I replaced the name here to anonymize the actual type…) but at this point we should have found the final information that will give us a better understanding of the problem, instead of the generic error 0xE06D7363.

Leave a Reply

Your email address will not be published.