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)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.