Stack unwinding in case of structured exceptions

This question provides more clarity on the problem described here. I did some more investigation and found that the stack unwinding is not happening in the following piece of code:

class One
{
public:
    int x ;
};

class Wrapper
{
public:
    Wrapper(CString csText):mcsText(csText)
    {
        CString csTempText;
        csTempText.Format("Wrapper constructor :: %s\n", mcsText);
        OutputDebugString(csTempText);
    }

    ~Wrapper()
    {
        CString csTempText;
        csTempText.Format("Wrapper destructor :: %s\n", mcsText);
        OutputDebugString(csTempText);
    }
    CString mcsText;
};
class Test
{
    public:

    void notifyError()
    {
        try
        {
            int x = 10; 
        }
        catch(...)  {}
    }

    void OnRecvBuffer()
    {
        try
        {
            Wrapper a("AddRef");    
            One* p = NULL;
            p->x = 10;
        }
        catch(...)
        {
            notifyError();
        }   
    }   
};



int main() 
{
    Test* pTest = new Test;

    pTest->OnRecvBuffer();

    OutputDebugString("Test");
}

I compiled this code using VC6 SP5 compiler and the output is "Wrapper constructor :: AddRef!!!" (i.e. the destructor of wrapper object which was constructed on stack is not called. Is this the expected behavior ? or is it a bug with VC compiler ? Can I use some compiler flags so that the stack unwinding happens in this case?

Answers


If you want to use SEH, you must use _set_se_translator function and /EHa compiler option.


The C++ standard does not give anything to work with in case of Undefined Behavior. Even if MS does. That's a platform specific thing -- so beware. Some such floating point exceptions are turned to Win32 exceptions which you can attempt to catch with _set_se_translator(). The problem is you can catch Win32 exceptions but then your stack will not be unwound properly. At least that is not something you can bet your life on. Wherein lies the futility of the exercise.

Update: The exception is thrown intentionally to check the stack unwinding. The question is why Wrapper class's destructor is not getting called. – Naveen

If this is the case -- don't do it. There are better ways to throw exceptions than via Undefined Behavior.

E.g:

void OnRecvBuffer()
{
    try
    {
        Wrapper a("AddRef");    
        throw 42; // this'll throw an exception without invoking UB
    }
    catch(...)
    {
        notifyError();
    }
}

You cannot dereference a NULL pointer. You are invoking Undefined Behavior here:

One* p = NULL;
p->x = 10;

After that line all bets are off and you could have killed us all ;)

p is a pointer to a One object. It should contain the address of an One object. You have initialized it to 0 -- there is no object at address 0. 0 is not a valid address for any object (this is guranteed by the standard).


Because C++ regular exception does not handle this kind of exception, you have to use SEH which does not know anything about the app and does not unwind.


This is undefined behavior:

One* p = NULL;
p->x = 10;

At this point the application is free to crash without unwinding the stack. If you want to test the stack unwinding replace this with:

 throw 42; // Life the Universe and Everything thrown away

You should not dynamically allocate all your objcts this is C++ not Java!

int main() 
{
    Test    pTest;   // Note the lack of new!

    pTest.OnRecvBuffer();

    OutputDebugString("Test");
}

Need Your Help

How do I iterate through a reference to an array of hashes in Perl?

arrays perl perl-data-structures hash

I have a reference to an array of hases that I pass to a subroutine in my perl script

when does java.util.zip.ZipFile.close() throw IOException?

java zip ioexception

Under what circumstances would java.util.zip.ZipFile.close() throw an IOException? Its method signature indicates that it can be thrown, but from the source code there doesn't seem to be any place ...