tags:

views:

299

answers:

4

I was debugging an application and encountered following code:

int Func()
{

 try 
 {

   CSingleLock aLock(&m_CriticalSection, TRUE);
   {
     //user code
   }
 }
 catch(...)
 {
     //exception handling
 }
 return -1;

}

m_CriticalSection is CCricialSection.

I found that user code throws an exception such that m_CriticalSection is not released at all. That means due to some reasons stack is corrupted and hence unwinding failed.

My question is: 1) In what different scenarios stack unwinding can fail ?

2) what different possibility of exception can be thrown such that stack unwinding fails.

3) Can I solve this problem by putting CSingleLock outside of try block ?

Thanks,

+3  A: 

Are you getting an abnormal program termination?

I believe your CCriticalSection object will be released CSingleLock's destructor. The destructor will get called always since this is an object on the stack. When the usercode throws, all stacks between the throw and the catch in your function will be unwound.

However, chances are that some other object in your user code or even the CSingleLock destructor has thrown another exception in the meantime. In this case the m_CriticalSection object will not get released properly and std::terminate is called and your program dies.

Here's some sample to demonstrate. Note: I am using a std::terminate handler function to notify me of the state. You can also use the std::uncaught_exception to see if there are any uncaught exceptions. There is a nice discussion and sample code on this here.

struct S {
    S() { std::cout << __FUNCTION__ << std::endl; }
    ~S() { throw __FUNCTION__; std::cout << __FUNCTION__ << std::endl;  }
};

void func() {
    try {
        S s;
        {
            throw 42;
        }
    } catch(int e) {            
         std::cout << "Exception: " << e << std::endl; 
    }
}

void rip() {
    std::cout << " help me, O mighty Lord!\n"; // pray
}

int main() {
    std::set_terminate(rip);
    try {
        func();
    }
    catch(char *se) {
        std::cout << "Exception: " << se << std::endl;
    }
}

Read this FAQ for clarity.

Can I solve this problem by putting CSingleLock outside of try block ?

Hard to say without having a look at the stack and error(s)/crashes. Why don't you give it a try. It may also introduce a subtle bug by hiding the real problem.

dirkgently
A: 

Let me start by saying that I don't know what CSingleLock and CCriticalSection do.

What I do know is that an exception thrown in your "user code" section should unwind the stack and destroy any variables that were created within the try { } block.

To my eyes, I would expect your aLock variable to be destroyed by an exception, but not m_CriticalSection. You are passing a pointer to m_CriticalSection to the aLock variable, but the m_CriticalSection object already exists, and was created elsewhere.

e.James
A: 
  • are you sure that lifetime of your m_CriticalSection is longer that CSingleLock?
  • maybe someone corrupt your stack?
  • 3) Can I solve this problem by putting CSingleLock outside of try block ?

    in this case - yes. But remember, it is not good thing for performance to put large block in mutex.

  • btw, catch(...) is not good practice in general. in Win32 it (catch(...)) catching SEH exceptions too, not only c++ exception. maybe you have core in this function and catch it with catch(...).

bb
VC++ catch (...) has not caught SEH exceptions since VC++2005.
Daniel Earwicker
Good news and nice addition :)
bb
A: 

My question is:
1) In what different scenarios stack unwinding can fail ?

2) what different possibility of exception can be thrown such that stack unwinding fails.

  • Exception thrown from constructor of throw expression
  • Exception thrown from destructor while exception propogating.
  • Exception thrown that is never caught (implementatin defined if this actually unwinds stack).
  • Exception thrown that is not specified in exception specification.
  • Exception thrown across a C ABI.
  • Exception thrown inside a thread that is not caught (Implementation defined what happens)

3) Can I solve this problem by putting CSingleLock outside of try block ?

No. All of the above cause the application to terminate without further unwinding of the stack.

Martin York