C++ SIGSEG和浮点保护的优先级
我已经编写了一个例程,它允许客户端在我的代码中加载和使用自己的dll。因为我无法控制客户端dll的质量,所以我试图清晰、简洁地报告我能想到的每个错误,否则他们会认为问题出在我的代码中 我有好几层保护,但现在似乎其中两层相互冲突 分段故障保护为:C++ SIGSEG和浮点保护的优先级,c++,memory,floating-point,operating-system,C++,Memory,Floating Point,Operating System,我已经编写了一个例程,它允许客户端在我的代码中加载和使用自己的dll。因为我无法控制客户端dll的质量,所以我试图清晰、简洁地报告我能想到的每个错误,否则他们会认为问题出在我的代码中 我有好几层保护,但现在似乎其中两层相互冲突 分段故障保护为: void (*previous_sigsegv_function)(int); // This caches the function that is currently encountered when a seg
void (*previous_sigsegv_function)(int); // This caches the function that is currently encountered when a segmentation fault is encountered.
previous_sigsegv_function = signal(SIGSEGV, terminate_immediately); // This registers with the OS the function to execute is a segmentation fault is encountered.
// Run client dll
signal(SIGSEGV, previous_sigsegv_function); // This resets the sigseg function to the original.
这在过去很有效(我不认为这是有争议的)
浮点保护有点困难(并导致这里提出了一些问题),但我最终将其编码为宏:
#define CATCH_FLOATING_POINT_EXCEPTION(EXPR, CONTROL, ERROR_FOUND) \
unsigned int __previous_control; \
_controlfp_s(&__previous_control, CONTROL, _MCW_EM); \
__try { \
EXPR; \
_controlfp_s(NULL, __previous_control, _MCW_EM); \
} \
__except (EXCEPTION_EXECUTE_HANDLER) \
{ \
strncpy_s(ERROR_FOUND, MAX_FP_ERROR_LENGTH, __describe_floating_point_error(GetExceptionCode()), MAX_FP_ERROR_LENGTH); \
_controlfp_s(NULL, __previous_control, _MCW_EM); \
}
然后这样使用:
CATCH_FLOATING_POINT_EXCEPTION(result = function(this->turbine_id), // DISCON_TYPEDEF returns an int.
SERIOUS_FP_EXCEPTIONS,
floating_point_error); // This is a char* to return the error (if there is one).
这也行得通
我最近创建了一个集成测试,似乎分段错误(通过故意使用损坏的指针创建)被错误地报告为除以零的错误
这是我的测试中的一个错误(比如在设法从不可靠的内存中生成一个除以零的过程中真的运气不好),还是两个错误捕获机制之间存在某种交互作用
编辑:
我相信这部分是因为我是如何产生分割错误的。我重做了它,这样它肯定会删除重要的内存,这会正确触发分段故障保护
但是,在调试模式下,它的行为完全符合预期(直接进入终止函数)。然而,在释放模式下,它同时记录被零除和分段故障。这是可以接受的行为,但有点奇怪
因此,我的问题是:为什么浮点机会被分段错误弄糊涂?可能更恰当的是:为什么SIGSEGV事件在发布模式下延迟,允许代码在终止之前报告浮点错误?我将自己回答这个问题,只是为了从“堆栈”中获取它:
这两种保护似乎以某种方式相互作用,但结果是SIGSEGV保护(最重要的一种)确实被触发。尽管浮点错误的附加警告毫无帮助且具有误导性,但它们并不是交易的破坏者。我在试图解决另一个问题时又回到了这个问题,现在我明白了这两种机制为什么会相互作用 SIGSEV保护位于外部,内部为浮点陷阱:
unsigned int _previous_floating_point_control; \
_controlfp_s(&_previous_floating_point_control, 0, 0); \
_controlfp_s(nullptr, CONTROL, _MCW_EM); \
__try { \
EXPR; \
_controlfp_s(nullptr, _previous_floating_point_control, _MCW_EM); \
} \
__except (EXCEPTION_EXECUTE_HANDLER) \
{ \
strncpy_s(ERROR_FOUND, MAX_FP_ERROR_LENGTH, _describe_floating_point_error(GetExceptionCode()), MAX_FP_ERROR_LENGTH); \
_controlfp_s(nullptr, _previous_floating_point_control, _MCW_EM); \
}
以及_descripe _floating _point _error函数:
inline const char* _describe_floating_point_error(DWORD code)
{
if (code && _EM_ZERODIVIDE)
return FP_ZERODIVIDE_DESCRIPTION;
...
return "Unknown floating point error";
}
在除法为零的情况下,此操作非常有效-GetExceptionCode返回一个包含_EM_ZERODIVIDE(0x00000008)的DWORD
但是,当出现更严重的错误时,例如sequementation错误,以及在我最近的例子中,dll中缺少的函数时,就会触发这个_except子句。在最后一种情况下,GetExceptionCode返回:
11000000011011010000000001111110
我还没有确定这代表了什么错误,但它确实包括_EM_ZERODIVIDE(即0000000000000000000000 1000),因此_descripe_floating_point_error错误地将其标识为除以零
我现在的问题是确定为什么GetExceptionCode在直接问题不相关(直接)时返回一个包含除法零标志的代码我希望否决这个问题的人能先发布一些有建设性的东西——对他们来说,这个问题显然没有价值,但这是一个困难的问题,我一直无法得到真正的答案。。。