Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 795
aJ. Avatar asked Dec 14 '22 05:12

aJ.


2 Answers

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).

like image 91
dirkgently Avatar answered Dec 28 '22 20:12

dirkgently


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

like image 35
Evgeny Lazin Avatar answered Dec 28 '22 18:12

Evgeny Lazin