Раскручивание стека в случае структурированных исключений

StackOverflow https://stackoverflow.com/questions/617809

Вопрос

Этот вопрос дает больше ясности по описанной проблеме. здесь.Я провел еще несколько исследований и обнаружил, что раскручивание стека не происходит в следующем фрагменте кода:

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");
}

Я скомпилировал этот код с помощью компилятора VC6 SP5, и на выходе получается «Конструктор оболочки::AddRef!!!" (т.е.деструктор объекта-оболочки, который был создан в стеке, не вызывается.Это ожидаемое поведение?или это ошибка компилятора VC?Могу ли я использовать какие-то флаги компилятора, чтобы в этом случае происходила раскрутка стека?

Это было полезно?

Решение

Если вы хотите использовать SEH, вы должны использовать функцию _set_se_translator и параметр компилятора / EHa.

Другие советы

Стандарт C++ не дает ничего, с чем можно было бы работать в случае неопределенного поведения.Даже если MS это сделает.Это специфичная для платформы вещь, так что будьте осторожны.Некоторые такие исключения с плавающей запятой превращаются в исключения Win32, которые вы можете попытаться перехватить с помощью _set_se_translator().Проблема в том, что вы можете перехватить исключения Win32, но тогда ваш стек не будет правильно развернут.По крайней мере, это не то, на что вы можете поставить свою жизнь.В этом и заключается бесполезность упражнения.

Обновлять:Исключение выбрасывается намеренно, чтобы проверить раскручивание стека.Вопрос в том, почему деструктор класса Wrapper не вызывается.- Навин

Если это так – не делайте этого.Есть более эффективные способы создания исключений, чем с помощью Undefine Behavior.

Например:

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

Вы не можете разыменовать NULL-указатель.Здесь вы вызываете неопределенное поведение:

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

После этой линии все ставки отменены, и вы мог убил нас всех ;)

p является указателем на One объект.Он должен содержать адрес One объект.Вы инициализировали его значением 0 — по адресу 0 нет объекта.0 не является допустимым адресом для любого объекта (это гарантируется стандартом).

Поскольку обычное исключение C ++ не обрабатывает такого рода исключения, вы должны использовать SEH, который ничего не знает о приложении и не раскручивает.

Это неопределенное поведение:

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

В этот момент приложение может завершить работу без разматывания стека.
Если вы хотите проверить раскрутку стека, замените это на:

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

Вы не должны динамически размещать все ваши объекты, это C ++, а не Java!

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

    pTest.OnRecvBuffer();

    OutputDebugString("Test");
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top