У меня есть приложение, написанное на C ++ в среде Linux. Приложение динамически загружает библиотеку (общий объект) во время выполнения. (Приложение получает команду пользователя и выполняет логику для динамической загрузки необходимой общей библиотеки.)
Есть ли способ предотвратить сбой и завершение работы приложения, когда происходит сбой или segfault в общей библиотеке?
Я хочу, чтобы мое приложение было активным, и сообщаю о сбое пользователю.
Как Не ответил вы могли бы установить (используя sigaction (2) с SA_SIGINFO
, не используйте сигнал (2)!) обработчик сигнала для SIGSEGV
, Тем не менее, внимательно прочитайте Сигнал (7) первый.
Обратите внимание, что если вы хотите полностью поймать SIGSEGV
(или другие асинхронные сигналы, такие как SIGBUS
, SIGILL
, SIGFPE
и т.д …) и продолжить обработку, это сложно и специфично для машины. Если вы вернетесь прямо из вашего SIGSEGV
то состояние машины остается прежним, и выполнение возвращается к машинной инструкции, которая вызвала SIGSEGV
который становится повторно запущенным до бесконечности (вы застряли в бесконечной петле).
Таким образом, чтобы иметь возможность продолжить выполнение, вы не должны либо возвращаться из обработчика сигнала, либо использовать siglongjmp (3) в нем, чтобы перейти к состоянию, ранее зарегистрированному в sigsetjmp (3), или измените состояние машины. Чтобы изменить состояние машины, вы можете изменить адресное пространство с помощью ММАП (2) и связанные вызовы, или вы можете изменить некоторые [сохраненные] регистры процессора, используя ucontext_t*
передается в качестве третьего аргумента вашему обработчику и запрашивает детализацию информации о сигнале, используя siginfo_t*
передан в качестве второго аргумента. Как это сделать, зависит от конкретной системы (зависит от операционной системы и процессора) и сложно.
Если вы хотите показать хороший обратный след от вашего обработчика сигнала, подумайте, например, об использовании. libbacktrace изнутри недавнего шара источника GCC. (Это будет работать намного лучше, если и программа, и плагин были скомпилированы с отладочной информацией, например, с gcc -O -g
)
Заметить, что Сигнал (7) прямо говорит, что только асинхронно-безопасные функции может быть вызван (прямо или косвенно) из обработчика сигнала. Так в принципе зовет malloc
, ::operator new
(который вызывается большинством Контейнеры C ++!!) или же printf
От обработчика сигнала это запрещено, и это не разумно. Однако, если вы просто позвоните libbacktrace
функция, а затем _exit (2) от вашего обработчика сигнала, это будет часто (но в принципе не всегда) работать.
Если вы хотите, чтобы ваше приложение сообщило об ошибке и Оставайся активным (например, если ваше приложение является сервером, чтобы иметь возможность продолжать обслуживать много запросов), это, вероятно, будет очень сложно (а иногда и невозможно). Например, если плагин глючит до такой степени, что испортил кучу, Вы должны убрать беспорядок (что не всегда возможно) …. В некоторых ситуациях я мог бы предположить, что единственное, что нужно сделать, это перезапустить приложение (например, вызвав execve (2) изнутри обработчик сигнала). Проверка приложения методы могут иметь значение: вы могли бы периодически разрабатывать приложение для контрольной точки и перезапускать из последнего сохраненного состояния …
В общем надежное восстановление после сбоя действительно сложно, специально для программного обеспечения C ++. Вы должны понимать много деталей реализации. Используя исключительно бесплатно программное обеспечение очень помогает: вы можете изучить детали во всех библиотеках (даже libstdc++
а также libc
: вам может понадобиться понять внутреннюю реализацию malloc
…).
Я даже не уверен, что это правильный подход для плагинов. Возможно, вы могли бы подумать о помощи разработчику плагина, например объясняя некоторые хорошо определенные правила кодирования, специфичные для приложения (или стиль программирования) и, возможно, разработка некоторых расширений компилятора GCC, например, с ПЛАВИТЬСЯ проверить некоторые из них во время компиляции плагина.
Да, это возможно. Если происходит ошибка, Ваша программа сначала получит SIGSEGV
(увидеть сигнал или так как сигнал устарел sigaction (2)). Подключив этот сигнал к обработчику, вы можете составить отчет о сбое.
void crash(int sig) {
cout << "report crash";
exit(sig);
}
int main() {
// connect signal to handler
signal(SIGSEGV, crash);
return 0;
}
Как отметил Джонатан Леффлер, это его комментарий, это всего лишь небольшое предложение, что делать. Есть несколько сигналов, которые нужно ловить не только SIGSEGV
, но, возможно, также SIGILL
, SIGFPE
… в зависимости от вашего приложения.