简体   繁体   English

在结构化异常的情况下展开堆栈

[英]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?我使用 VC6 SP5 编译器编译了这段代码,output 是“包装器构造函数::AddRef ...”(即?没有调用在堆栈上构造的包装器 object 的析构函数?这是预期的行为吗?还是它VC 编译器的错误?我可以使用一些编译器标志,以便在这种情况下发生堆栈展开吗?

The C++ standard does not give anything to work with in case of Undefined Behavior. C++ 标准没有提供任何可用于未定义行为的情况。 Even if MS does.即使 MS 有。 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() .一些这样的浮点异常被转换为 Win32 异常,您可以尝试使用_set_se_translator()来捕获这些异常。 The problem is you can catch Win32 exceptions but then your stack will not be unwound properly.问题是您可以捕获 Win32 异常,但是您的堆栈将无法正确展开。 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.问题是为什么 Wrapper 类的析构函数没有被调用。 – Naveen – 纳文

If this is the case -- don't do it.如果是这种情况 - 不要这样做。 There are better ways to throw exceptions than via Undefined Behavior.有比通过未定义行为更好的方法来引发异常。

Eg:例如:

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

You cannot dereference a NULL pointer.您不能取消引用 NULL 指针。 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. p是指向One object 的指针。 It should contain the address of an One object.它应该包含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).您已将其初始化为 0 - 地址 0 处没有 object。0 不是任何 object 的有效地址(这是由标准保证的)。

If you want to use SEH, you must use _set_se_translator function and /EHa compiler option.如果要使用 SEH,则必须使用 _set_se_translator function 和 /EHa 编译器选项。

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.因为 C++ 常规异常不处理此类异常,所以您必须使用对应用程序一无所知且不会展开的 SEH。

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!您不应该动态分配所有对象,这是 C++ 而不是 Java!

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

    pTest.OnRecvBuffer();

    OutputDebugString("Test");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM