Stack unwinding in case of structured exceptions
Asked Answered
R

4

5

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?

Registry answered 6/3, 2009 at 6:13 Comment(0)
M
4

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

Mouflon answered 6/3, 2009 at 6:41 Comment(0)
E
8

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

Embrasure answered 6/3, 2009 at 6:24 Comment(5)
The exception is thrown intentionally to check the stack unwinding. The question is why Wrapper class's destructor is not getting called.Appraisal
As I have pointed out that is UB -- what happens when you invoke UB is not defined. No point discussing that. There are other better ways to throw exceptions.Embrasure
The example program invoked what is undefined behavior for standard C++, but the question is about Microsoft SEH (Structured Exception Handling), not standard C++ exceptions.Banksia
I can figure that out. But a) SEH is never mentioned in OP's question. b) doing things wrong don't make it a right.Embrasure
So, stop downvoting my answer since this is perfectly correct.Embrasure
M
4

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

Mouflon answered 6/3, 2009 at 6:41 Comment(0)
G
2

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.

Giorgio answered 6/3, 2009 at 6:30 Comment(0)
O
0

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");
}
Oringa answered 6/3, 2009 at 8:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.