我在 MinGW-w64 中发现了 SJLJ 和 SEH 异常处理之间的一个区别:只要在运行时执行了至少一个 try{} 块,由 signal() 函数设置的 C 信号处理程序就不会在 SJLJ 版本中工作。由于这个问题似乎没有在任何地方描述,我把它放在这里记录一下。
以下示例 (test_signals.cpp) 演示了这一点。
// This sample demonstrates how try {} block disables handler set by signal()
// on MinGW-w64 with GCC SJLJ build
#include <signal.h>
#include <iostream>
int izero = 0;
static void SIGWntHandler (int signum)//sub_code)
{
std::cout << "In signal handler, signum = " << signum << std::endl;
std::cout << "Now exiting..." << std::endl;
std::exit(1);
}
int main (void)
{
std::cout << "Entered main(), arming signal handler..." << std::endl;
if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
std::cout << "signal(OSD::SetSignal) error\n";
if (signal (SIGFPE, (void(*)(int))SIGWntHandler) == SIG_ERR)
std::cout << "signal(OSD::SetSignal) error\n";
if (signal (SIGILL, (void(*)(int))SIGWntHandler) == SIG_ERR)
std::cout << "signal(OSD::SetSignal) error\n";
// this try block disables signal handler...
try { std::cout << "In try block" << std::endl; } catch(char*) {}
std::cout << "Doing bad things to cause signal..." << std::endl;
izero = 1 / izero; // cause integer division by zero
char* ptrnull = 0;
ptrnull[0] = '\0'; // cause access violation
std::cout << "We are too lucky..." << std::endl;
return 0;
}
构建:
g++ test_signals.cpp -o test_signals.exe
预期的输出是:
Entered main(), arming signal handler...
In try block
Doing bad things to cause signal...
In signal handler, signum = 8
Now exiting...
当我使用 MigGW-w64 SJLJ 变体构建时的实际输出是:
Entered main(), arming signal handler...
In try block
Doing bad things to cause signal...
应用程序会在延迟一段时间后静默终止。也就是说,信号处理程序不会被调用。如果 try{} 块被注释掉,信号处理程序会被正确调用。
当使用 MinGW-w64 SEH 变体时,它的行为符合预期(信号处理程序被调用)。
我不清楚为什么会出现这个问题,因此如果有人能给出解释,我将不胜感激。