Поймать необработанное исключение C ++ в обработчике сигнала и возобновить приложение - PullRequest
0 голосов
/ 22 октября 2018

Сначала немного контекста:

Я проверяю работоспособность некоторого C-написанного сервиса, работающего во встроенном Linux.Все мои тесты написаны на C ++ и вызывают C API сервиса.

Обратите внимание, что служба и приложение работают в 2 отдельных процессах.Приложение открывает прокси в своем контексте для связи со службой через tcp / ip.

Чтобы проверить, что плохо закодированный обратный вызов не может сломать сервис, я даю ему функцию, которая просто генерирует исключение C ++.Как и ожидалось, создание исключения в этом C-обратном вызове приводит к сбою приложения.

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

Когда я говорю, что приложение аварийно завершает работу, я имею в виду, что оно получает сигнал SIGABRT, вот вызов стека из gdb:

(gdb) info stack
0  0x4c22cb94 in raise () from /lib/libc.so.6
1  0x4c230670 in abort () from /lib/libc.so.6
2  0xb6e9e6c4 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/libstdc++.so.6
3  0xb6e9c214 in ?? () from /usr/lib/libstdc++.so.6
4  0xb6e9c288 in std::terminate() () from /usr/lib/libstdc++.so.6
5  0xb6e9c5ac in __cxa_throw () from /usr/lib/libstdc++.so.6
6  0x0011824c in LocationTest::crashingLocCb (location=<optimized out>)
at ../../../TestLibrary/200-Location/src/locationtest.cpp:427
7  0x00144f64 in locationCb (location=<optimized out>)
at ../../PAL/src/tms/pallocationprovider.cpp:109
8  0xb6fbdb50 in locationcallback_thread (thread_info=0x1a82b8)
at ../lib_c/src-gen/location_proxy.c:273
9  0x4c33defc in ?? () from /lib/libpthread.so.0

Что я хотел бы сделать сейчас:

Я хочу поймать сигнал SIGABRT и возобновить тестовое приложение, чтобы пойти дальше (у службы проверки не нарушено какое-то внутреннее состояние;проверьте, что это не вызвало утечку и т. д.)

Каков наилучший подход, чтобы иметь что-то максимально чистое?

Это должно быть сделано с помощью обработчика сигнала, но не повредит ли это другим работающим потокам?Каков наилучший способ отправки информации, пойманной в обработчике сигналов, в соответствующий поток?

(у меня пока мало опыта работы с этими сигналами posix)

1 Ответ

0 голосов
/ 26 октября 2018

Вот как я решил свою проблему (в псевдокоде).Возможно, были и другие способы, у меня все еще открыты уши:

void malfunction()
{

    terminate_handler previousTerminateHandler = set_terminate(callbackUnhandledExceptionTerminateHandler);

    registerCallback(throwingCb);
    launchTheTest();
    waitForErrorEvent();
    saveTheResult();
    doSomeCleanUp();

    set_terminate(previousTerminateHandler);

    return;
}

static void callbackUnhandledExceptionTerminateHandler()
{
    try{ throw; }
    catch(const exception& e) { 
        cout << e.what() << endl;
        notifyTheErrorEvent();
    }catch(...){
        cout << "callbackUnhandledExceptionTerminateHandler : else ???" << endl;
        abort();
    }

    //Log whatever information, you need such as pid, stack or whatever
    cout << "processId = " << getpid() << endl;

    //Here if you return from this handler, it will call abort();
    //You could let it ends, if you already logged what you needed.
    //You could also trap the thread, if this is something you already do elsewhere before stopping the application.

}

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

В более общем случае эту же обработку можно использовать для печати стека при необработанном исключении, без необходимости использования gdb.

...