Могу ли я игнорировать SIGFPE в результате деления на ноль?

StackOverflow https://stackoverflow.com/questions/419527

Вопрос

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

Есть ли способ игнорировать это?

Я пытался использовать

#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 поверх кода сбоя, тогда я бы также рекомендовал изменить код, чтобы он умер другим способом. Если вы этого не сделаете, вы можете попробовать установить

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top