Download as pdf or txt
Download as pdf or txt
You are on page 1of 19

Exception Handling

This Exception Handling is not part of the standard C. It's


only supported by Microsoft as Extension to C for windows
platform only.

SEH
SEH stands for structured Exception Handling.

Provide a robust (healthy, strong) mechanism to respond to the


unexpected asynchronous events such as addressing
exception, arithmetic faults and system errors.

Advantages of SEH
You can deallocate resources in case of error instead of leaving
it to the OS.

However, if exception isn't severe you can also continue.

Also do error recovery.

SEH ensures that the program will be able to free resources


and perform other cleanup processing before the block,
thread, or process terminates either under program control or
because of an unexpected exception.

SEH allows specification of a code block, or exception handler,


which can delete the temporary files, perform other
termination operations, and analyze and log the exception.
Filter Exceptions
There are three predefined values for filter exceptions

1. EXCEPTION_EXECUTE_HANDLER

This filter simply tells to execute the except block.

2. EXCEPTION_CONTINUE_SEARCH

This tells to not execute the first except block and pass it to
search for the next except block.

3. EXCEPTION_CONTINUE_EXECUTION

It simply returns the control from where exception was


generated. Not exactly at the line where exception was
generated but to the next line. Doesn't execute the body of
the except.

REMEMBER!

All the custom Exception Handle Filter function will always


return one of these values and must return them.

Difference between Errors and


Exceptions?
Errors are synchronous.

Occur at known locations occasionally (sometimes).

Example:

System Call Error.

Exceptions are asynchronous.

Occur at anywhere and is not possible and practical to test.


Example:

Division by zero and memory access violations.

Termination Handler
A termination handler serves much the same purpose as an
exception handler, but it is executed when a thread leaves a
block as a result of normal program flow as well as when an
exception occurs.

On the other hand, a termination handler cannot diagnose an


exception

Termination handlers, like exception handlers, are a


convenient way to close handles, release resources,
restore masks, and otherwise restore the process to a
known state when leaving a block.

For example, a program may execute return statements in the


middle of a block, and the termination handler can perform
the cleanup work.

Termination handlers do not execute if a process or thread


terminates (ExitProcess(), ExitThread(), TerminateProcess(),
TerminateThread(), c exit())

Therefore, a process or thread should not execute one of these


functions inside a try-except or try-finally block.
Can you write an except as well as
finally for a single try?
No, here you can either define a try or except of a single try.

1. What will be the output for below


code?
__try
{
_tprintf(_T("First try\n"));
__try
{
_tprintf(_T("Second try\n"));
int a;
int b = 0;
_tprintf(_T("Exception is going to
occur\n"));
a = 2 / b;
_tprintf(_T("Exception is made\n"));
}
__finally
{
_tprintf(_T("finally\n"));
}

}
__except (EXCEPTION_EXECUTE_HANDLER)
{
_tprintf(_T("Parent Exception\n"));
}

Output

First try
Second try

Exception is going to occur

finally

parent Exception

On Exception, first the __finally will be executed attached


directly to the __try in which exception is raised. Then, it will
look for the parent exception handler, and that will be
executed.

More precisely, on exception in try it first look for exception


handler and it come across the parent exceptional handler
which have __except (EXCEPTION_EXECUTE_HANDLER) which
say go first execute your __finally then come to me.

2. What will be the output of the


following code?
DWORD FilterFunction()
{
   printf("1 ");                     // printed
first
   return EXCEPTION_EXECUTE_HANDLER;
}
int _tmain(int argc, LPTSTR argv[])
{
   __try
  {
       __try
      {
           RaiseException(
               1,                    // exception
code
               0,                    // continuable
exception
               0, NULL);             // no
arguments
      }
       __finally
      {
           printf("2 ");             // this is
printed second
      }
  }
   __except (FilterFunction())
  {
       printf("3\n");                // this is
printed last
  }
   return 0;
}

Output
As exception raises it will go to find the exception handle it
come across the custom exceptional handler method
FilterFunction() which gets executed and return the
EXCEPTION_EXECUTE_HANDLER which says go execute your
finally first and come back then the rest __except code gets
executed.

3. What will be the output of the


following code?
int _tmain(int argc, LPTSTR argv[])
{
  __try
  {
       __try
      {
           RaiseException(
               1,                    // exception
code
               0,                    // continuable
exception
               0, NULL);             // no
arguments
      }
       __finally
      {
           printf("2 ");             // this is
printed second
      }
  }
   __except (EXCEPTION_CONTINUE_SEARCH)
  {
       printf("3\n");                // this is
printed last
  }
   return 0;
}

Output

Basically, EXCEPTION_CONTINUE_SEARCH will end up calling


window exception handler as there is no other exception
handler define which will terminate the program by first calling
the __finally method.

4. What will be the output of the


following code?
int _tmain(int argc, LPTSTR argv[])
{
   __try
  {
       __try
      {
           __try
          {
               RaiseException(
                   1,                    //
exception code
                   0,                    //
continuable exception
                   0, NULL);             // no
arguments
          }
           __finally
          {
               printf("2 ");             // this is
printed second
          }
      }
       __except (EXCEPTION_CONTINUE_SEARCH)
      {
           printf("3\n");                // this is
printed last
      }
  }
   __except (EXCEPTION_EXECUTE_HANDLER)
  {
       printf("4\n");                // this is
printed last
  }
   return 0;
}

Output

5. What will be the output of following


code?
DWORD FilterFunction()
{
   printf("1 ");                     // printed
first
   return EXCEPTION_EXECUTE_HANDLER;
}
int _tmain(int argc, LPTSTR argv[])
{
   __try
  {
       __try
      {
           __try
          {
               RaiseException(
                   1,                    //
exception code
                   0,                    //
continuable exception
                   0, NULL);             // no
arguments
          }
           __finally
          {
               printf("2 ");             // this is
printed second
          }
      }
       __except (EXCEPTION_CONTINUE_SEARCH)
      {
           printf("3\n");                // this is
printed last
      }
  }
   __except (FilterFunction())
  {
       printf("4\n");                // this is
printed last
  }
   return 0;
}

Output
6. What will be the output of the
following code?
DWORD FilterFunction()
{
   printf("1 ");                     // printed
first
   return EXCEPTION_EXECUTE_HANDLER;
}
int _tmain(int argc, LPTSTR argv[])
{
   __try
  {
       __try
      {
           __try
          {
               RaiseException(
                   1,                    //
exception code
                   0,                    //
continuable exception
                   0, NULL);             // no
arguments
               printf("after raising exception\n");
          }
           __finally
          {
               printf("2 ");             // this is
printed second
          }
      }
       __except (EXCEPTION_CONTINUE_EXECUTION)
      {
           printf("3\n");                // this is
printed last
      }
  }
   __except (FilterFunction())
  {
       printf("4\n");                // this is
printed last
  }
   return 0;
}

Output

7. What will be the output of following


code?
__try
{
_tprintf(_T("First try\n"));
__try
{
_tprintf(_T("Second try\n"));
int a;
int b = 0;
_tprintf(_T("Exception is going to
occur\n"));
a = 2 / b;
_tprintf(_T("Exception is made\n"));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
_tprintf(_T("Parent Exception\n"));
}
__finally
{
_tprintf(_T("finally\n"));
}

}
__except (EXCEPTION_EXECUTE_HANDLER)
{
_tprintf(_T("Parent Exception\n"));
}

Output

Error

Error because You can't have both except as well as finally for
a single __try.

8. What is the output of following code?


__try
{
_tprintf(_T("First try\n"));
__try
{
_tprintf(_T("Second try\n"));
int a;
int b = 0;
_tprintf(_T("Exception is going to
occur\n"));
a = 2 / b;
_tprintf(_T("Exception is made\n"));
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
_tprintf(_T("Parent Exception\n"));
}

Output

Error

You can't have a try without except and __finally, you need to
have one of them.

9. What will be the output of following


code?
int _tmain(int argc, LPTSTR argv[])
{
_tprintf(_T("Welcome TO MS Visual Code
2019\n"));

int i;

for (i = 0; i < 10; i++) __try {


_tprintf(_T("In for loop\n"));
}
__finally {
_tprintf(_T("In finally turn %d\n"), i);
}
getchar();
return 0;
}

Output

__try is attached to the for loop. We can say that the entire for
loop body is inside the __try.

Understanding Report Exception


VOID ReportException (LPCTSTR userMessage, DWORD
exceptionCode)

/* Report as a non-fatal error.


Print the system error message only if the
message is non-null. */
{
if (lstrlen (userMessage) > 0)
ReportError (userMessage, 0, TRUE);
/* If fatal, raise an exception. */

if (exceptionCode != 0)
RaiseException (
(0x0FFFFFFF & exceptionCode) |
0xE0000000, 0, 0, NULL);//E for error

return;
}

Every thing is quite easy to understand except this line

RaiseException ((0x0FFFFFFF & exceptionCode) |


0xE0000000, 0, 0, NULL);//E

Basically, as you can see in the image


In 0x0FFFFFFF 0 are the last bits while F are the First bit. As per
the above image in order to raise an error exception the Last
Byte must be E and for info it should be 6 as you can see in
image above. So, in this line we are just making sure that the
last byte should always be E.

How can we identify that the exception


is user generated or Microsoft
generated?
We know that the user generated exception code 29th bit is
always set to 1. If the 29th bit of the exception code is 1 then
it's user generated exception else it's a Microsoft exception.

For example:

if ((0x20000000 & exCode) != 0) { //bit 29 is set


for customer generated exception
/* User Exception. */
*eCategory = 10;
return EXCEPTION_EXECUTE_HANDLER;
}

The 2 will set the 29th bit to 1 and doing and with exCode will
let us know it's the user exception or not.

How exceptions are handle in


multithreading?
Exception occur in a thread is handle by that thread itself. An
exception occur in one thread cannot be handle by another
thread.
Decoding
GetExceptionInformation() ?
Basically, just like GetExceptionCode() we can not call this
function inside the __except body because it can override the
most recent exception. Basically, what we do is we call it in the
following way

__except (Filter (GetExceptionInformation (),


&eCategory))

Here, Filter is a user defined function.

Now, let's look into GetExceptionInformation() function.


Retrieves a computer-independent description of an exception,
and information about the computer state that exists for the
thread when the exception occurs.

The GetExceptionInformation() return a pointer to an


EXCEPTION_POINTERS structure that contains pointers to the
following two structures:

EXCEPTION_RECORD structure that contains a description


of the exception.
CONTEXT structure that contains the computer state
information.

We are mostly interested in EXCEPTION_RECORD structure.


typedef struct _EXCEPTION_RECORD {
 DWORD                    ExceptionCode;
 DWORD                    ExceptionFlags;
 struct _EXCEPTION_RECORD *ExceptionRecord;
 PVOID                    ExceptionAddress;
 DWORD                    NumberParameters;
 ULONG_PTR              
 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;

Here, most important for us is ExceptionCode.

However, an interesting thing is ExceptionFlags help us let


know that the exception can be continued or not.

You might also like