Rob Earhart's WebLog

SEH Ordering

A number of devs don't quite understand the order of operations in structured exception handling.  This leads to some interesting bugs...

Take this snippet of pseudocode, for example:

try {
    EnterCriticalSection();

    try {
        DoSomething()
        RaiseException();
        DoSomethingElse();

    } finally {
        LeaveCriticalSection();
    }
} except(ExceptionFilter()) {
    ReportException();
}

Assuming that ExceptionFilter() returns EXCEPTION_EXECUTE_HANDLER, in what order will these functions be called?


It goes like this:
EnterCriticalSection();
DoSomething();
RaiseException();
ExceptionFilter();
LeaveCriticalSection();
ReportException();

... that is, the exception filter--which is deciding how to deal with the exception--is called before the termination handlers on the stack are executed.

This is pretty obvious if you recall that with a continuable exception, the filter may return EXCEPTION_CONTINUE_EXECUTION, causing execution to resume from the point where the exception was raised.  In that case, DoSomethingElse() would be called, and you wouldn't want to have left the critical section--that'll happen when DoSomethingElse() returns.

The implications get interesting.

If an exception filter is wrapping code the author doesn't control (say, it's making a call into some other dll), it can't know very much about the state of the thread and the system.  The thread might be impersonating, it might be holding locks, who knows?

This limits what the exception filter can do.  For instance, if the thread faulted in the heap, it might be holding the heap lock (since the heap lock's dropped in a termination handler); another thread might be holding the loader lock and attempting to acquire the heap lock, so if the faulting thread blocks on the loader lock, it'll deadlock.

It takes some thought to get this right.  The moral is, unless you fully understand and control the code your exception filter is wrapping, you can't make assumptions about the state of the system in your exception filter.

(Standard Microsoft disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights.)

Published Thursday, November 11, 2004 7:23 PM by earhart
Filed under:

Comments

 

michkap said:

So which would the correct answer here? Would it be better to have the inside handler do the exception handling and put the finally block in the outside handler? That is my gut reaction, but I could be missing something.

Great to see you here!
December 5, 2004 9:40 PM
 

Rob Earhart said:

Reversing the nesting doesn't help--if the exception handler's on the inside, the filter will still be called while the lock's held.

(The only change would be that, if the filter were to return EXCEPTION_EXECUTE_HANDLER, the finally block would execute normally--AbnormalTermination() would return FALSE.)

In the general case, there's no way to switch them around even if you wanted to--imagine if the try/finally block were in a separate function, called from within the outer try/except.

This is the situation with the kernel32.dll unhandled exception filter, for instance. The unhandled exception filter will be called before any of the finally blocks on the stack are executed--which is appropriate, since the filter may fix the problem and continue execution, and you wouldn't want to have executed the finally blocks in that case.

(Standard Microsoft disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights.)
December 7, 2004 10:54 AM
Anonymous comments are disabled

© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker