Могу ли я игнорировать SIGFPE в результате деления на ноль?
-
03-07-2019 - |
Вопрос
У меня есть программа, которая намеренно выполняет деление на ноль (и сохраняет результат в переменную), чтобы остановить в определенных обстоятельствах. Однако я хотел бы иметь возможность отключить эту остановку, не меняя макрос, который выполняет деление на ноль.
Есть ли способ игнорировать это?
Я пытался использовать
#include <signal.h>
...
int main(void) {
signal(SIGFPE, SIG_IGN);
...
}
но он все еще умирает с сообщением "Исключение с плавающей запятой (ядро сброшено)". Р>
Я на самом деле не использую значение, поэтому мне все равно, что присвоено переменной; 0, случайный, неопределенный ...
РЕДАКТИРОВАТЬ: я знаю, что это не самый портативный, но он предназначен для встроенного устройства, которое работает на многих различных ОС. Действие остановки по умолчанию - делить на ноль; другие платформы требуют других приемов для принудительной перезагрузки, вызванной сторожевым таймером (например, бесконечный цикл с отключенными прерываниями). Для тестовой среды ПК (linux) я хотел отключить остановку деления на ноль, не полагаясь на такие вещи, как assert. Р>
Решение
Зачем вам намеренно выполнять деление на ноль, чтобы остановить? Не могли бы вы exit (-1)
или другой эквивалент?
Особенно, если вам не нужен результат деления на 0, это просто не имеет смысла.
Другие советы
Хорошо, во-первых, вы должны использовать sigaction (2) вместо устаревшего signal ()
.
Во-вторых, использование SIGFPE в целях прекращения программы явно абсурдно, так как вы должны подавать сигнал, такой как SIGTERM или SIGUSR1, вместо того, чтобы настраивать какой-то другой сигнал для его побочного эффекта и игнорировать его семантическое значение. И, более конкретно, на странице справки для sigaction (2) есть раздел NOTES с рекламой, посвященной SIGFPE, которая указывает один или два способа, которыми вы намеренно не используете его.
Что вам нужно сделать, это поднять (3) сигнал, когда вы хотите завершить. Затем используйте поле sa_handler
в структуре sigaction
, чтобы изменить, игнорировать ли ( SIG_IGN
) или завершить ( SIG_DFL
) на этот сигнал.
int main(void) { struct sigaction my_action; my_action.sa_handler = SIG_IGN; my_action.sa_flags = SA_RESTART; sigaction(SIGUSR1, &my_action, NULL); raise(SIGUSR1); /* Ignored */ my_action.sa_handler = SIG_DFL; sigaction(SIGUSR1, &my_action, NULL); raise(SIGUSR1); /* Terminates */ return 0; }
Тем не менее, я не понимаю, почему вы используете сигналы вместо простого exit ()
.
Проверьте возвращаемое значение
signal(SIGFPE, SIG_IGN);
Если вы получаете SIG_ERR
, проверьте значение errno
, чтобы узнать, что пошло не так. Это все, что вы можете сделать переносимо.
Я знаю, что вы не хотите менять деление на ноль, но это непереносимо и нелогично. Вы хотите выполнить coredump, если возникает какое-либо условие, но иметь возможность отключить это поведение без редактирования кода? Используйте assert
и NDEBUG
.
Это не переносимо, но на x86 вы можете управлять FPU:
Использование gcc в Linux (я уверен, что другие компиляторы имеют аналогичные возможности):
#include <fpu_control.h>
_FPU_SETCW (_FPU_DEFAULT);
Поскольку для _FPU_DEFAULT по умолчанию установлено _FPU_MASK_ZM (ZM обозначает Zero-Divide-Mask).
void handler(int trapId)
{
// Whatever
}
signal(SIGFPE, handler);
Не могли бы вы заставить программу выйти через менее вымышленное выражение? Например:
#include <signal.h>
#ifdef DEBUG
#define DIE_HERE raise(SIGFPE)
#else
#define DIE_HERE
#endif
Я бы не решился переопределить поведение по умолчанию, чтобы какая-то другая часть вашей программы не была непреднамеренно разделена на ноль. В качестве альтернативы, если вы заставляете его выходить таким образом, чтобы получить дамп ядра, вы можете захотеть использовать точки останова в отладчике. Или, если вы находитесь в системе с отладчиком gdb, утилита gcore может быть полезна.
Если у вас есть контроль над кодом сбоя, я бы также рекомендовал изменить код, чтобы он умер другим способом. Если вы этого не сделаете, вы можете попробовать вместо этого установить пустой обработчик сигнала (т. Е. Использовать сигнал (SIGFPE, & amp; EmptyFunction
)), но вы по-прежнему полагаетесь на неопределенное поведение, поэтому нет гарантии он по-прежнему будет работать в других системах или в других версиях ядра или библиотеки C.
lnmiit l поверх кода сбоя, тогда я бы также рекомендовал изменить код, чтобы он умер другим способом. Если вы этого не сделаете, вы можете попробовать установить