Почему плавающее исключение «деление на ноль» не было поймано в функции, даже если был установлен обработчик? - PullRequest
1 голос
/ 24 июня 2010

Я пытался научиться обрабатывать сигналы в C, когда обнаружил странное поведение.Когда х / = у;выполняется в контексте основной функции обработчик сигнала.Но когда то же самое, выполняемое в некотором обработчике функции (bad_func), игнорируется, однако обработчик сигнала для SIGFPE уже установлен.

Q: Почему SIGFPE не был пойман в функцию моим глобальным обработчиком сигнала, даже когда был вызван _control87?

(MS VC 2010):

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <float.h>

jmp_buf g_jb_MainFunc;

void hook_zd (int i)
{
    printf("Result :%i\n",i);
    longjmp(g_jb_MainFunc, 5);
}
void bad_func(void)
{
    double x = 0., y = 0.;
    puts("hello1");
    //abort();
    x /= y;
    puts("bye1");
}
int main(int argc, char* argv[])
{
    double x = 0., y = 0.;
    signal(SIGFPE, hook_zd);
    signal(SIGABRT, hook_zd);
    puts("hello");
    _control87(0, _MCW_EM );
    int res;
    if (! (res = setjmp(g_jb_MainFunc)))
    {
        //abort();
        //x /= y;
        bad_func();
    } else
    {
        printf("Jumped here from: %i\n",res);
    }
    puts("bye");

    return 0;
}

1 Ответ

2 голосов
/ 24 июня 2010

Это работает для меня, если я не компилирую с включенными оптимизациями. Например, если я скомпилирую его из командной строки как cl mysigtest.cpp, исключения будут работать, как и ожидалось. Но если я скомпилирую cl /O1 mysigtest.cpp, то это не исключение.

В разобранном коде показана проблема:

?bad_func@@YAXXZ (void __cdecl bad_func(void)):
  00000000: 68 00 00 00 00     push        offset ??_C@_06CKBHOFLC@hello1?$AA@
  00000005: E8 00 00 00 00     call        _puts
  0000000A: 68 00 00 00 00     push        offset ??_C@_04EEFJMNKA@bye1?$AA@
  0000000F: E8 00 00 00 00     call        _puts
  00000014: 83 C4 08           add         esp,8
  00000017: C3                 ret

Разделение было оптимизировано. Попробуйте с отключенными оптимизациями или измените bad_func на следующее. Для меня это "победил" оптимизатор:

double bad_func(double y)
{
    double x = 0.; 
    puts("hello1");
    //abort();
    x /= y;
    puts("bye1");
    return x;
}

И поменяй звонок на него:

bad_func( 0.0 );
...