Получение информации о том, где исключения c ++ выбрасываются внутри блока catch? - PullRequest
8 голосов
/ 12 июня 2010

У меня есть приложение на c ++, которое упаковывает большие части кода в блоки try. Когда я ловлю исключения, я могу вернуть пользователя в стабильное состояние, что приятно. Но я больше не получаю аварийные дампы. Мне бы очень хотелось выяснить, где в коде происходит исключение, поэтому я могу его зарегистрировать и исправить.

Идея получить дамп без остановки приложения была бы идеальной, но я не уверен, что это возможно.

Есть ли какой-нибудь способ, которым я могу выяснить, где было выброшено исключение из блока catch? Если это полезно, я использую родной msvc ++ на Windows XP и выше. Мой план состоит в том, чтобы просто записывать сбои в файл на компьютерах различных пользователей, а затем загружать сбои, как только они достигнут определенного размера.

Ответы [ 5 ]

6 голосов
/ 12 июня 2010

Это возможно при использовании SEH (структурированная обработка исключений). Дело в том, что MSVC реализует исключения C ++ через SEH. С другой стороны, чистый SEH гораздо более мощный и гибкий.

Вот что ты должен сделать. Вместо использования чистых C ++ блоков try / catch, таких как:

try
{
    DoSomething();
} catch(MyExc& exc)
{
    // process the exception
}

Вы должны обернуть внутренний кодовый блок DoSomething блоком SEH:

void DoSomething()
{
    __try {
        DoSomethingInner();
    }
    __except (DumpExc(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) {
        // never get there
    }
}

void DumpEx(EXCEPTION_POINTERS* pExc)
{
    // Call MiniDumpWriteDump to produce the needed dump file
}

То есть внутри блока try / catch в C ++ мы помещаем еще один необработанный блок SEH, который только выводит все исключения, но не перехватывает их.

См. здесь для примера использования MiniDumpWriteDump.

4 голосов
/ 12 июня 2010

Возможно создать ваши исключения, включив в них имена исходных файлов и номера строк.Для этого вам нужно создать класс, производный от std::exception для хранения информации.В приведенном ниже примере у меня есть библиотека исключений для моего приложения, включая my_exception.У меня также есть traced_error, который является классом исключений шаблона, полученным из моих исключений уровня приложения.Исключение traced_error содержит информацию о имени файла и номере строки и вызывает метод класса исключений уровня приложения 'what() для получения подробной информации об ошибке.

#include <cstdlib>
#include <string>
#include <stdexcept>
#include <iostream>
using namespace std;


template<class EX>
class traced_error : virtual public std::exception, virtual public EX
{
public:
    traced_error(const std::string& file, int line, const EX& ex)
    :   EX(ex),
        line_(line),
        file_(file)
    {       
    }

    const char* what() const
    {
        std::stringstream ss;
        static std::string msg;
        ss << "File: " << file_ << " Line: " << line_ << " Error: " << EX::what();
        msg = ss.str().c_str();
        return msg.c_str();
    }

    int line_;
    std::string file_;
};

template<class EX> traced_error<EX> make_traced_error(const std::string& file, int line, const EX& ex)
{
    return traced_error<EX>(file, line, ex);
}


class my_exception : virtual public std::exception
{
public:
    my_exception() {};

    const char* what() const
    {
        return "my_exception's what";
    }
};

#define throwx(EX) (throw make_traced_error(__FILE__,__LINE__,EX))


int main()
{
    try
    {
        throwx(my_exception());
    }
    catch( const std::exception& ex )
    {
        cout << ex.what();
    }
    return 0;
}

Вывод этой программы:

Файл:. \ Main.cpp Строка: 57 Ошибка: my_exception's what

Вы также можете изменить дизайн так, чтобы исключения уровня приложения происходили из traced_error вместонаоборот, если вы предпочитаете ловить определенные исключения уровня приложения.В вашем catch вы можете записать ошибку в файл журнала и создать файл дампа, используя MiniDumpWriteDump () .

2 голосов
/ 12 июня 2010

Вы можете создавать дампы, используя функцию MiniDumpWriteDump .

Если вы используете исключения C ++, вы можете просто включить информацию о файле / строке / функции (так что вы увидите ее в виде текста, если вызовете std :: exception.what ()) в любом месте, куда вы ее бросаете исключение (с использованием макросов ____FUNCTION____, ____FILE____ и ____LINE____).

Если вы пытаетесь перехватить исключения ОС, то, вероятно, лучшим вариантом будет сбой приложения.

1 голос
/ 12 июня 2010

Один трюк, который не зависит от компилятора, - это обернуть оператор throw в функцию.Функция может выполнять другие обязанности перед выдачей исключения, например, запись в файл журнала.Это также делает удобным местом для установки точки останова.Если вы создаете макрос для вызова функции, вы можете автоматически включать __FILE__ и __LINE__, где произошел выброс.

1 голос
/ 12 июня 2010

Вам нужно проанализировать стек, чтобы выяснить, откуда возникло исключение.Для msvc есть библиотека с именем dbghelp.dll , которая может помочь вам выйти из системы при исключениях.В общем случае я выхожу из файла minidump и использую его для воспроизведения проблемы рядом с использованием правильной базы данных программы (файл pdb).Это работает на системах клиентов, которые не поставляются с исходным кодом или которым вы не хотите давать pdbs.

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