【发布时间】:2010-10-02 05:40:51
【问题描述】:
例子
int *ptr;
*ptr = 1000;
我可以在不使用任何微软特定的情况下使用标准 C++ 捕获内存访问冲突异常吗?
【问题讨论】:
例子
int *ptr;
*ptr = 1000;
我可以在不使用任何微软特定的情况下使用标准 C++ 捕获内存访问冲突异常吗?
【问题讨论】:
读完就哭!
我想通了。如果你不从处理程序中抛出,处理程序将继续,异常也将继续。
当你抛出自己的异常并处理它时,魔法就会发生。
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Signal %d",signal);
throw "!Access Violation!";
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGSEGV , SignalHandler);
try{
*(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
}
catch(char *e)
{
printf("Exception Caught: %s\n",e);
}
printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
printf("But please kids, DONT TRY THIS AT HOME ;)\n");
}
【讨论】:
sigaltstack)(除非 C++ 异常展开实现允许它),并且处理展开机制本身的每个运行时函数都应该是信号安全的。
signal(SIGSEGV, SIG_DFL);
在 Visual Studio 中使用 try -> catch (...) 块有一种非常简单的方法可以捕获任何类型的异常(除以零、访问冲突等)。一个小的项目设置调整就足够了。只需在项目设置中启用 /EHa 选项。请参阅项目属性 -> C/C++ -> 代码生成 -> 将 Enable C++ Exceptions 修改为“Yes With SEH Exceptions”。就是这样!
在此处查看详细信息: https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160
【讨论】:
不。当你做坏事时,C++ 不会抛出异常,这会导致性能下降。访问冲突或除以零错误之类的事情更像是“机器”异常,而不是您可以捕获的语言级别的事情。
【讨论】:
至少对我来说,另一个答案中提到的signal(SIGSEGV ...) 方法不适用于带有 Visual C++ 2015 的 Win32。 对我有用的是使用eh.h 中的_set_se_translator()。它的工作原理是这样的:
第 1 步)确保在Project Properties / C++ / Code Generation / Enable C++ Exceptions 中启用Yes with SEH Exceptions (/EHa),正如 Volodymyr Frytskyy 的回答中提到的那样。
第 2 步)调用 _set_se_translator(),为新异常 translator 传入一个函数指针(或 lambda)。它之所以称为翻译器,是因为它基本上只是将低级异常作为更容易捕获的东西重新抛出,例如std::exception:
#include <string>
#include <eh.h>
// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
std::string error = "SE Exception: ";
switch (u) {
case 0xC0000005:
error += "Access Violation";
break;
default:
char result[11];
sprintf_s(result, 11, "0x%08X", u);
error += result;
};
throw std::exception(error.c_str());
});
第 3 步)像往常一样捕捉异常:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
【讨论】:
这种情况取决于实现,因此需要供应商特定的机制才能进行陷阱。对于 Microsoft,这将涉及 SEH,而 *nix 将涉及信号
虽然捕获访问冲突异常通常是一个非常的坏主意。几乎没有办法从 AV 异常中恢复,尝试这样做只会导致更难在程序中找到错误。
【讨论】:
如前所述,在 Windows 平台上没有非 Microsoft/编译器供应商的方式来执行此操作。但是,以正常的 try { } catch (exception ex) { } 方式捕获这些类型的异常显然是有用的,用于错误报告和更优雅的应用程序退出(正如 JaredPar 所说,应用程序现在可能有麻烦了) .我们在一个简单的类包装器中使用 _se_translator_function,它允许我们在 try 处理程序中捕获以下异常:
DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)
原始类来自这篇非常有用的文章:
【讨论】:
不是异常处理机制, 但是你可以使用 C 提供的 signal() 机制。
> man signal
11 SIGSEGV create core image segmentation violation
写入 NULL 指针可能会导致 SIGSEGV 信号
【讨论】:
signal() 是 posix 标准的一部分。 Windows 实现了 posix 标准(Linux 和 unix 也是如此)
这样的违规意味着代码存在严重错误,并且不可靠。我可以看到一个程序可能想要尝试以一种希望不会覆盖以前的数据的方式保存用户的数据,希望用户的数据还没有损坏,但是根据定义没有标准方法处理未定义的行为。
【讨论】: