views:

487

answers:

5

I have a object of CCriticalSection in my class to synchronize the exceptions to a method. I use it with CSingleLock object like this:

void f()
{
  try
   {
     CSingleLock lock(&m_synchronizer, TRUE);
     .....
     .....

   }

  catch(SomeException )
  {
  }

  catch(...)
  {
  }

}

The critical section object is properly unlocked if any of the statement throws a C++ exception, however if I get any other type of exception (something like a access violation) is there any way I can unlock my critical section? I don't think RAII will help here as the stack unwinding doesn't happen. Is there any thing I can do to prevent the critical section being in locked state after exiting the function f?

+2  A: 

RAII does help here. The most important thing to not here is "going out of scope" is not necessarily just stack unwinding. When the try block is exited, either normally or through an exception, the destructor will be called. Anytime your variable goes out of scope its destructor is invoked.

Edit

Hmm it appears the question has been edited to focus on SEH (non C++ exceptions). In this case the destructor code might not be fired. However, as others have pointed out, most of the non-C++ exceptions are equivalent to application crashes. It may not be reasonable to react to these exceptions in any sane way other than to crash. In this case your app is exited and your critical section will be destroyed anyway.

See @JaredPar's answer for a good solution for translating C SEH exceptions to C++ exceptions for Windows.

Doug T.
I don't think the destructor of lock object will be called in case of structured exceptions.
Naveen
@Naveen, this depends on your compiler settings. They will be called if you enable ASYNC exception handling.
JaredPar
@Naveen, C++ exceptions are SEH exceptions. The only difference between catch and __catch is the former will only catch a subset of cases. In any case, why not test?
Richard
@Richard - C++ exceptions are *not* structured exceptions, though the compiler has the option to turn SEH exceptions into C++ exceptions.
Michael Burr
+3  A: 

EDIT Update

The destructor of CSingleLock will indeed unlock the underlying critical section. Access violations and the like are called SEH exceptions. As to whether or not the destructor will run in the face of an SEH exception is very environment specific. There are tricks you can do to make this type of scenario work.

For instance, one option is to translate all SEH exceptions into a corresponding C++ exception. I blogged recently on the technique to accomplish this. Once they're all C++ exceptions then the destructor being called is guaranteed.

But another question is why bother doing this? Once you're faced with at access violation the only thing your program can reliably do is crash.

JaredPar
Even CSingleLock does it. Isn't it?
Naveen
@Naveen, looking into that. I'm unfamiliar with that class (spent more of my time with the ATL versions).
JaredPar
Looks like a nice blog article on this - I'll have to read it more closely later. However, catching and handling SEH exceptions can be useful, especially for validating parameters (and especially when dealing with being called from untrusted code, such as plugins). You can return an error instead of crashing in this case, and do it reliably. At least reasonably reliably.
Michael Burr
Very nice article @JaredPar. +1.
Doug T.
nice blog @JaredPar, glad to know at least 2 out of 4 of the answers to this question were entered via Dvorak. Fight the power!
Doug T.
But even if you crash, some resources are so limited/critical that they absolutely must be released (and correctly) (That up-link to the ISS for instance). In these cases it would be very useful to force stack unwinding with a C++ exception.
Martin York
@Martin, are you talking about Mutex instances shared across process's? If so, the process exit should cause the OS to free the locks appropriately. I know Windows will and I'm fairly certain *nix does as well (been awhile though so I can't speak absolutely). Is there a difference type of resource you're talking about that I'm missing?
JaredPar
+2  A: 

Assuming you're using MSVC try compiling with the /EHa command line option which maps Windows' structured exceptions to C++ exceptions (the C++ docs sometimes call them 'asynchronous' exceptions).

You should read up on the implications of this - I don't use the option myself, and I'm not sure what the drawbacks might be.

You could also try using the __try, __except, __finally keywords to handle SEH yourself.

Michael Burr
If you use __try etc., it won't let you create any object with non-trivial destructors in that function
James Hopkin
Ah - then you're stuck with either using /EHa, doing a lot of restructuring of code, or using something like what JaredPar wrote about on his blog.
Michael Burr
A: 

If you really need your application to survive when a particular area of code performs an access violation, you should consider having that code in a separate process.

If code is trying to read or write to places it's not allowed, what's to stop it writing into other parts of your application's memory, causing all sorts of nasty problems?

James Hopkin
A: 

AFAIK, you NEVER should use CCriticalSection nor any MFC synchronization object.

Ryan