LINUX.ORG.RU

Как в qt msvc при crash не дать упасть приложению ?

 , , ,


0

4

Подскажите как можно в qt msvc проекте, когда случаются ошибки access violation, не дать проге упасть. То есть хочу словить это исключение и обработать, чтобы прога не рухнула из-за него. Можно ли это как-то сделать в qt msvc ловить исключения. Хочу их в лог записывать.

Исключения ловятся try .. catch.

А access violation это не исключения, это баги, когда ты с памятью явно как-то не так работаешь.

Если сам не видишь в чём проблема, попробуй всякими PVS-Studio, clang-tidy и cppcheck прогнать свой код, может они подскажут где ты ошибся

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Вот я и хочу поймать в try ... catch любой крэш проги. Но qt msvc не генерирует исключения. Ollydbg говорит, что acess violation это тоже исключение, которое генерится при обращении по несуществующему адресу.

user2132 ★
() автор топика
Ответ на: комментарий от RazrFalcon

На qt это никак не решается ? Нельзя ли собрать qt из сорцов с поддержкой исключений ? Чтобы любой крэш можно было отловить и не дать упасть приложению ?

user2132 ★
() автор топика
Ответ на: комментарий от anonymous

Не работает вот на таком тесте

    QByteArray ans;
    ans.at(5); //не ловит тут исключение

user2132 ★
() автор топика
Ответ на: комментарий от user2132

Вот я и хочу поймать в try ... catch любой крэш проги.

Как уже сказали выше, SIGSEGV - это не C++-исключение (а сигнал), значит, его нельзя словить таким образом. Но сигнал отловить можно. Разве что продолжить исполнение программы после именно этого сигнала - дело не тривиальное. А вот получить stacktrace можно.

gag ★★★★★
()
Ответ на: комментарий от gag

Разве что продолжить исполнение программы после именно этого сигнала - дело не тривиальное.

Запускаешь в обработчкие сигнала QGuiApplication::run() у сохраненного в глобальную переменную QApplication и делов.

Только вот работать корректно оно, конечно, не будет. Но оно и сейчас корректно не работает.

P.S. Не пытайтесь так делать, этот пост относиться к категории вредных советов.

trex6 ★★★★★
()

Запустить под отладчиком, когда приложение упадёт появится окошко. Там будут кнопки продолжить, повторить и прервать. Точно не помню названия, винды нет под рукой. Нажимаешь повторить и у тебя в QtCreator отладчик остановиться в месте краша.

ox55ff ★★★★★
()
Последнее исправление: ox55ff (всего исправлений: 1)
Ответ на: комментарий от ox55ff

Да остановился после кнопки Повторить, а как теперь еще стек трейс собирать на таких местах автоматом. У меня прога после кнопки Повторить попадает в catch блок. Если я там напишу снятие дампа, будет ли это правильно, так как это уже после кнопки Повторить.

LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{
    //And output crash information
    EXCEPTION_RECORD *record = pException->ExceptionRecord;
    QString errCode("0x" + QString::number(record->ExceptionCode, 16));
    QString errAddr("0x" + QString::number((uint)record->ExceptionAddress, 16));
    //QString errFlag("0x" + QString::number(record->ExceptionFlags, 16));
    //QString errPara("0x" + QString::number(record->NumberParameters, 16));

    QString str;

    str.append("Sorry ! Crash Happen\r\n\r\n");
    str.append("Error Code        : " + errCode + "\r\n");
    str.append("Error Address   : " + errAddr + "\r\n");

    QMessageBox::critical(NULL, "Crash Happen", str, QMessageBox::Close);

    // here is to save the memories currenlty.
    QString dumpfilename = "../crash.dump";

    HANDLE hDumpFile = CreateFile((LPCWSTR)dumpfilename.utf16(),
             GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if(hDumpFile != INVALID_HANDLE_VALUE) {
        qDebug() << "Create File Succeed";
        MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
        dumpInfo.ExceptionPointers = pException;
        dumpInfo.ThreadId = GetCurrentThreadId();
        dumpInfo.ClientPointers = TRUE;
        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                          hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
        CloseHandle(hDumpFile);
    } else {
        qDebug() << "Create File Failed";
    }

    return EXCEPTION_EXECUTE_HANDLER;
}
__declspec(noinline) void TestExceptions()
{
    QByteArray ans;
    ans.at(5);
}

int main()
{
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
    __try
    {
        TestExceptions();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Executing SEH __except block\r\n");
    }

    return 0;
}

Вот в ApplicationCrashHandler не попадает после нажатия Повторить.
user2132 ★
() автор топика
Ответ на: комментарий от RazrFalcon

ООМ - это исключение. Так и обрабатывать.

Ха-ха-ха. Нет!

Только так, как по ссылке (проблема с Jetty там нерелевантная) и никак иначе:

https://stackoverflow.com/q/5792049/314015

Состояние VM после OOM - это кромешный пипец, в котором может отвалиться все что угодно и который лучше даже палкой не трогать.

anonymous
()
Ответ на: комментарий от user2132

У тебя падает из-за индекса, который выходит за границы массива? Или что?

Если мы говорим про C++, то возможности перехватить, обработать и продолжить работу ограничены исключениями c++. Если у тебя access violation, то забудь. ЦПП это тебе не управляемые языки по типу C# или JAVA. Тут всё строго.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Конкретно сейчас не падает, просто хотел на случай если упадет, чтобы сделала стеки всех тредов. Прогу запускают на ночь. Как лучше тут защищаться от случайных падений ? Реализовывать алгоритм восстановления работы после крэша ? Задача проги в течение суток опрашивать датчики, и результаты писать в файлы.

user2132 ★
() автор топика
Ответ на: комментарий от user2132

С access violation дальше работать не получится. Падать и запускаться заново.

Я у себя использую boost::stacktrace. Он умеет дамп записывать. Есть пример в документации. Правда я его ни разу не пытался расшифровать )))). Исключение ловлю в обработчике сигнала. Не помню как точно. В линуксе и в винде разными способами ловлю. Вот это попробуй https://stackoverflow.com/a/3911102

ox55ff ★★★★★
()
Ответ на: комментарий от user2132

Постоянно прогоняй свою программу через valgrind или его аналоги. На винде прямо самого valgrind нет, но точно есть аналоги (интел??). На маке - хрен пойми что сейчас творится, особенно с этой каталиной. На линуксе valgrind очень хорош. В общем, если пишешь на C++, то обязательно используй всякие анализаторы, трассировщики и т.п.

Или бери Java с C# вместо всего этого. Тут можно подставить другие языки с GC. Может, даже питон сгодится для твоей задачи. Кстати, как ни странно, но в третьем питоне тоже есть GC, но такой своеобразный, я бы сказал.

dave ★★★★★
()
Ответ на: комментарий от dave

А что скажете про Visual Leak Detector и heob ? Попробовал ими прогонять, но из минусов показывают утечки памяти внутри qt объектов, чем забивают лог бесполезной инфой.

user2132 ★
() автор топика
Ответ на: комментарий от ox55ff

Да handler поставил на сигнал, а есть нормальный код по дампу, который сунуть в этот обработчик ? Я вот такой пихнул, но чет криво там делает и расшифровщик не вытаскивает из него стек трейсов:

LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{
    //And output crash information
    EXCEPTION_RECORD *record = pException->ExceptionRecord;
    QString errCode("0x" + QString::number(record->ExceptionCode, 16));
    QString errAddr("0x" + QString::number((uint)record->ExceptionAddress, 16));
    //QString errFlag("0x" + QString::number(record->ExceptionFlags, 16));
    //QString errPara("0x" + QString::number(record->NumberParameters, 16));

    QString str;

    str.append("Sorry ! Crash Happen\r\n\r\n");
    str.append("Error Code        : " + errCode + "\r\n");
    str.append("Error Address   : " + errAddr + "\r\n");

    QMessageBox::critical(NULL, "Crash Happen", str, QMessageBox::Close);

    // here is to save the memories currenlty.
    QString dumpfilename = "../crash.dmp";

    HANDLE hDumpFile = CreateFile((LPCWSTR)dumpfilename.utf16(),
             GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if(hDumpFile != INVALID_HANDLE_VALUE) {
        qDebug() << "Create File Succeed";
        MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
        dumpInfo.ExceptionPointers = pException;
        dumpInfo.ThreadId = GetCurrentThreadId();
        dumpInfo.ClientPointers = TRUE;
        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                          hDumpFile, MiniDumpWithFullMemory, &dumpInfo, NULL, NULL);
        CloseHandle(hDumpFile);
    } else {
        qDebug() << "Create File Failed";
    }

    return EXCEPTION_EXECUTE_HANDLER;
}
А если руками дамп делаю из taskmgr, то нормально расшифровывается.

user2132 ★
() автор топика
Ответ на: комментарий от RazrFalcon

ООМ - это исключение. Так и обрабатывать.

Есть два нюанса:

  • ООМ может выскочить практически в любом месте программы
  • Чтобы обработать ООМ зачастую нужна память, например, чтобы сконструировать исключение и передать его обработчику

Было бы интересно посмотреть на пример какого-нибудь кода на нормальном языке (к коим си и сипласплас, само собой, не относятся), который бы при ООМ выдавал бы какое-нибудь человекочитаемое сообщение.

Laz ★★★★★
()
Ответ на: комментарий от dave

valgrind

На моём жирном проекте с обработкой видео он подыхает. А вот санитайзеры очень сильно помогают. Только вот у ТС винда. Я не знаю есть там аналоги.

ox55ff ★★★★★
()
Ответ на: комментарий от user2132

Я бустом снимаю. Хз как на winapi это делается.

ox55ff ★★★★★
()
Ответ на: комментарий от Laz

ООМ может выскочить практически в любом месте программы

Как и любое другое исключение.

Чтобы обработать ООМ зачастую нужна память

Нужна. Но проблема в данном случае будет только если у нас 100500 мелких объектов. Если нам не удалось выделить 100 метров, то обработать это исключение не проблема.

RazrFalcon ★★★★★
()
Ответ на: комментарий от user2132

А что скажете про Visual Leak Detector и heob ? Попробовал ими прогонять, но из минусов показывают утечки памяти внутри qt объектов, чем забивают лог бесполезной инфой.

Про винду не скажу. На C++ я программировал в основном на линуксе.

В Qt запросто могут быть утечки. Они, вообще, везде могут быть, даже в системе. Еще бывает, что глобальная память засоряется, которая выделена под процесс, но тот же valgrind о ней как-то особо оповещает, потому что это может быть нормой для приложения или библиотеки.

Тут дело не только в утечках. Там иногда и некорректные обращения по памяти вылавливаются (как раз твой случай?). Когда стек портится и все такое.

dave ★★★★★
()
Ответ на: комментарий от dave

Постоянно прогоняй свою программу через valgrind или его аналоги. На винде прямо самого valgrind нет, но точно есть аналоги (интел??).

https://drmemory.org/ есть, он и под Linux работает

SZT ★★★★★
()
Ответ на: комментарий от SZT

А как прикрутить google breakpad к проекту qt ? Добавил по инструкции в проект файлы: crash_handler.h и crash_handler.cpp, скопировал src папку в свой проект и прописал в .pro файле пути к сорцам из src папки. Но падает на компоновщике:

Создается библиотека debug\Test3.lib и объект debug\Test3.exp
crash_handler.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall google_breakpad::ExceptionHandler::ExceptionHandler(class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > const &,bool (__cdecl*)(void *,struct _EXCEPTION_POINTERS *,struct MDRawAssertionInfo *),bool (__cdecl*)(wchar_t const *,wchar_t const *,void *,struct _EXCEPTION_POINTERS *,struct MDRawAssertionInfo *,bool),void *,int)" (??0ExceptionHandler@google_breakpad@@QAE@ABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@P6A_NPAXPAU_EXCEPTION_POINTERS@@PAUMDRawAssertionInfo@@@ZP6A_NPB_W5123_N@Z1H@Z) в функции "public: void __thiscall Breakpad::CrashHandlerPrivate::InitCrashHandler(class QString const &)" (?InitCrashHandler@CrashHandlerPrivate@Breakpad@@QAEXABVQString@@@Z)
crash_handler.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall google_breakpad::ExceptionHandler::~ExceptionHandler(void)" (??1ExceptionHandler@google_breakpad@@QAE@XZ) в функции "public: void * __thiscall google_breakpad::ExceptionHandler::`scalar deleting destructor'(unsigned int)" (??_GExceptionHandler@google_breakpad@@QAEPAXI@Z)
crash_handler.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: bool __thiscall google_breakpad::ExceptionHandler::WriteMinidump(void)" (?WriteMinidump@ExceptionHandler@google_breakpad@@QAE_NXZ) в функции "public: bool __thiscall Breakpad::CrashHandler::writeMinidump(void)" (?writeMinidump@CrashHandler@Breakpad@@QAE_NXZ)
debug\Test3.exe : fatal error LNK1120: неразрешенных внешних элементов: 3
Он каких-то либ не находит ?

user2132 ★
() автор топика
Ответ на: комментарий от SZT

Please report this at http://drmemory.org/issues along with the results of running '-debug -dr debug'.

ERROR: cannot find DynamoRIO library C:\DrMemory-Windows-2.2.0-1\bin\debug\lib32\debug\dynamorio.dll

И dll действительно там нет, как и папки lib32

Нет, это мертворожденное чудовище лучше закопать.

anonymous
()
Ответ на: комментарий от anonymous

Это все при компиляции примера в конце требует libbreakpad.a, которую я не особо понял как без танцов с бубном на винде собрать. На линуксе легко собрал всего 2 командами: configure и make.

user2132 ★
() автор топика
Ответ на: комментарий от user2132

ээ, нет - не требует. Там исходники гугловской либы напрямую подключаются в pri файле. Только в vendor папку закинуть содержимое git breakpad. Только минидамп супер бесполезный какой-то. Нормальный стек трейс только для breakpad обработчика есть.

https://dropmefiles.com/oecsx

anonymous
()
Ответ на: комментарий от anonymous

У меня получилось с mingw qt собрать проект с breakpad, но чет при попытке смены на msvc он не собирается и требует зависимости.

user2132 ★
() автор топика
Ответ на: комментарий от anonymous

Твой пример собрался на msvc, но чет креш дампы ни qtcreator не хочет подключать, ни анализатор dumpdiag нормально не анализирует. Почему-то dumpdiag показывает просто адреса вместо имен функций.

user2132 ★
() автор топика
Ответ на: комментарий от anonymous

А как символы сгенерил для примера ? У меня чет dump_sums не хочет работать.

dump_syms.exe crashdump.pdb
CoCreateInstance CLSID_DiaSource {E6756135-1E65-4D17-8576-610761398C3C} failed (msdia*.dll unregistered?)
Open failed

user2132 ★
() автор топика
Ответ на: комментарий от user2132

dump_syms.exe C:\prj\breakpad-master\crashdump\dumps\crashdump.pdb > crashdump.sym

Couldn't locate EXE or DLL file.

У меня тоже не хочет.

https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt

If you don't have MSVC 2013 available on you system (more specifically msdia120.dll) you will be greeded with the following output when attempting to use dump_syms: CoCreateInstance CLSID_DiaSource failed (msdia*.dll unregistered?)

Называется - тряси бубном веселее.

anonymous
()
Ответ на: комментарий от anonymous

Ага, дальше видимо тока по адресу в дизассемблерном виде искать. Я попробовал скачать msdia120.dll и зарегать эту либу, но чет все равно не хочет работать.

user2132 ★
() автор топика
Ответ на: комментарий от user2132

Но procdump,если че, просто работает без краноглазых бубнов.

anonymous
()
Ответ на: комментарий от ox55ff

Только вот у ТС винда. Я не знаю есть там аналоги.

В clang должны работать

annulen ★★★★★
()

Пытаться ловить ошибки памяти в коде, который ты отдаёшь пользователю — плохая идея. Их надо выловить при отладке.

В линуксе есть valgrind. (Под виндой есть Dr.Memory, но как замена валгринду он так себе.)

Ну и всякие статические анализаторы, которые тебе назвали выше.

Задача проги в течение суток опрашивать датчики, и результаты писать в файлы.

Ууу, нет. Никаких алгоритмов восстановления. Код должен быть отлажен. В том числе суточным тестированием на имитаторах этих самых датчиков.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.