Причины сбоя при размотке стека - PullRequest
0 голосов
/ 05 марта 2009

Я отлаживал приложение и обнаружил следующий код:

int Func()
{

 try 
 {

   CSingleLock aLock(&m_CriticalSection, TRUE);
   {
     //user code
   }
 }
 catch(...)
 {
     //exception handling
 }
 return -1;

}

m_CriticalSection - это CCricialSection.

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

Мой вопрос: 1) При каких сценариях разматывание стека может завершиться неудачей?

2) какая другая возможность исключения может быть выброшена так, что разматывание стека завершается неудачей.

3) Можно ли решить эту проблему, поместив CSingleLock вне блока try?

Спасибо

Ответы [ 4 ]

2 голосов
/ 05 марта 2009

Вы получаете аварийное завершение программы?

Я верю, что ваш CCriticalSection объект будет освобожден деструктором CSingleLock. Деструктор будет вызываться всегда, так как это объект в стеке. Когда выбрасывает код пользователя, все стеки между throw и перехватчиком в вашей функции будут разматываться.

Однако есть вероятность, что какой-то другой объект в вашем пользовательском коде или даже деструктор CSingleLock выдал еще одно исключение. В этом случае объект m_CriticalSection не будет освобожден должным образом, и будет вызван std::terminate, и ваша программа умрет.

Вот пример для демонстрации. Примечание: я использую функцию обработчика std::terminate, чтобы уведомить меня о состоянии. Вы также можете использовать std::uncaught_exception, чтобы увидеть, есть ли какие-либо необъяснимые исключения. Здесь есть хорошее обсуждение и пример кода здесь .

struct S {
    S() { std::cout << __FUNCTION__ << std::endl; }
    ~S() { throw __FUNCTION__; std::cout << __FUNCTION__ << std::endl;  }
};

void func() {
    try {
        S s;
        {
            throw 42;
        }
    } catch(int e) {            
         std::cout << "Exception: " << e << std::endl; 
    }
}

void rip() {
    std::cout << " help me, O mighty Lord!\n"; // pray
}

int main() {
    std::set_terminate(rip);
    try {
        func();
    }
    catch(char *se) {
        std::cout << "Exception: " << se << std::endl;
    }
}

Читайте это FAQ для ясности.

Можно ли решить эту проблему, поместив CSingleLock за пределы блока try?

Трудно сказать, не глядя на стек и ошибки (с) / сбои. Почему бы тебе не попробовать? Это может также внести небольшую ошибку, скрывая реальную проблему.

0 голосов
/ 06 марта 2009

Мой вопрос:
1) При каких разных сценариях разматывание стека может завершиться неудачей?

2) какая другая возможность исключения может быть выброшена так, что разматывание стека завершится неудачей.

  • Исключение, выброшенное из конструктора выражения броска
  • Исключение, выброшенное из деструктора при распространении исключения.
  • Исключение, которое никогда не перехватывается (определяется, если это действительно раскручивает стек).
  • Исключение, которое не указано в спецификации исключения.
  • Исключение для C ABI.
  • Исключение, создаваемое в потоке, который не перехватывается (реализация определяет, что происходит)

3) Можно ли решить эту проблему, поместив CSingleLock вне блока try?

Нет. Все вышеперечисленное заставляет приложение завершать работу без дальнейшего раскручивания стека.

0 голосов
/ 05 марта 2009
  • Вы уверены, что время жизни вашего m_CriticalSection больше, чем у CSingleLock?
  • Может быть, кто-то испортил ваш стек?
  • 3) Можно ли решить эту проблему, поместив CSingleLock вне блока try?

    в данном случае - да. Но помните, что для производительности нехорошо помещать большой блок в мьютекс.

  • Кстати, поймать (...) в целом не очень хорошая практика. в Win32 это (catch (...)) тоже ловит исключения SEH, не только исключение c ++. возможно у вас есть ядро ​​в этой функции и выловите его с помощью catch (...).

0 голосов
/ 05 марта 2009

Позвольте мне начать с того, что я не знаю, что делают CSingleLock и CCriticalSection.

Что я знаю, так это то, что исключение, выброшенное в разделе «код пользователя» , должно размотать стек и уничтожить все переменные, созданные в блоке try {}.

На мой взгляд, я ожидаю, что ваша переменная aLock будет уничтожена исключением, но не m_CriticalSection. Вы передаете указатель на m_CriticalSection в переменную aLock, но объект m_CriticalSection уже существует и был создан в другом месте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...