Under what circumstances does EXCEPTION_RECORD link to another nested exception?

272 views Asked by At

The documentation for _EXCEPTION_RECORD says about one of it's members, struct _EXCEPTION_RECORD *ExceptionRecord

A pointer to an associated EXCEPTION_RECORD structure. Exception records can be chained together to provide additional information when nested exceptions occur.

However, I haven't been able to provoke such a situation of nested structured exceptions. Here is what I have tried so far:

#include <iostream>
#include <windows.h>

void Handle0(LPEXCEPTION_POINTERS pex) {
    std::cout << "chain0 = " << pex->ExceptionRecord->ExceptionRecord << std::endl;
}

void Handle1(LPEXCEPTION_POINTERS pex) {
    std::cout << "chain1 = " << pex->ExceptionRecord->ExceptionRecord << std::endl;
    __try {
        throw 3;
    } __except( Handle0(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER ) {}
}

int main() {
    __try {
        throw 3;
    } __except( Handle1(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER ) {}
    return 0;
}

The pex->ExceptionRecord->ExceptionRecord is always nullptr. Under what circumstances do I get a link to a nested _EXCEPTION_RECORD there?

1

There are 1 answers

1
Alex On

According to MSDN:

When an exception is raised during the processing of an exception filter within ... native code ... a nested exception is raised, the ExceptionRecord field in the EXCEPTION_RECORD structure (as returned by GetExceptionInformation) is set, and the ExceptionFlags field sets the 0x10 bit. The following example illustrates this difference in behavior:

#include <windows.h>
#include <stdio.h>
#include <assert.h>

#ifndef false
#define false 0
#endif

int *p;

int filter(PEXCEPTION_POINTERS ExceptionPointers) {
   PEXCEPTION_RECORD ExceptionRecord =
                     ExceptionPointers->ExceptionRecord;

   if ((ExceptionRecord->ExceptionFlags & 0x10) == 0) {
      // not a nested exception, throw one
      *p = 0; // throw another AV
   }
   else {
      printf("Caught a nested exception\n");
      return 1;
    }

   assert(false);

   return 0;
}

void f(void) {
   __try {
      *p = 0;   // throw an AV
   }
   __except(filter(GetExceptionInformation())) {
      printf_s("We should execute this handler if "
                 "compiled to native\n");
    }
}

int main() {
   __try {
      f();
   }
   __except(1) {
      printf_s("The handler in main caught the "
               "exception\n");
    }
}

I believe it is also set if you try to continue non-continuable exception. In this case EXCEPTION_RECORD will represent EXCEPTION_NONCONTINUABLE_EXCEPTION, while its ExceptionRecord will point to original exception.