【问题标题】:Catch the "Access violation reading location 0x00000000" exception捕获“访问冲突读取位置 0x00000000”异常
【发布时间】:2015-08-28 15:31:35
【问题描述】:

我正在使用来自 3rd 方 dll 的方法,它会引发“访问冲突读取位置 0x00000000”异常。我无法深入研究,所以我只是想知道是否有办法抓住它,所以不要折叠应用程序。我尝试了以下 4 种方法,但均无效。

1,

try
    {
    sts = resFilter->initialize(m_JPEG2000File); // it throws that exception
    }
    catch (...){
        printf("Gotcha0...");
        int a = 34;
    }

2、3 和 4

LONG WINAPI CrashHandler1(EXCEPTION_POINTERS * a/*ExceptionInfo*/)
{  std::cout << "Gotcha1!" << std::endl;
return 0;
}

void CrashHandler2()
{    std::cout << "Gotcha2!" << std::endl;}

void CrashHandler3()
{    std::cout << "Gotcha3!" << std::endl;}

// in Main()
::SetUnhandledExceptionFilter(CrashHandler1);
std::set_terminate (CrashHandler2);
std::set_unexpected( CrashHandler3 );

Test(); // It would throw "Access violation reading location 0x00000000" exception 

如果我调试它,就会抛出异常。如果我在运行时运行它,“Gotcha1!”将显示在控制台中,但应用程序仍会崩溃。有什么办法可以吃这个例外吗?

提前致谢,

编辑:

@Adriano Repetti 提到 __try 和 __except 可以捕获此异常。

感谢你们不吃那个例外!

我有一个调用该项目的外部 C# 可执行文件。我想捕获这个异常,这样我就有机会记录错误并且不折叠 C# 应用程序。我仍然会终止这个非常 C++ 进程。我在 C# 中循环数据,每次都会从头开始一个新的 C++ 进程,所以它会是一个新的 C++ 实例。所以阿德里亚诺的方法对我有用。

【问题讨论】:

  • 尝试使用 __try__except(访问冲突不是 C++ 的已知),但我建议做。你不知道发生了什么,你不知道已经执行了什么,内存(和数据!)甚至在你的代码中也可能被破坏。
  • 顺便说一句,甚至可能是您的代码破坏了他们的数据...
  • 如果你使用 MSVC++ 那么你可以简单地改变一个编译选项,使用 /EHa 并且 catch (...) 会吃掉。不要再次运行该代码,它会吃掉你的午餐。电话永远是解决这个问题的最佳方式,当你打电话给这个库的程序员时,一定要准备一个小的 repro 项目。
  • 感谢阿德里亚诺和汉斯,我会马上尝试。如果我加载另一个文件一切正常,所以我确定异常是从他们的程序集内部抛出的。我正在打开一个文件夹中的所有文件,如果有问题我只想跳过它并进入下一个。所以我觉得“吃”这个例外对我来说是相对安全的。
  • @Adriano Repetti,谢谢 __try 作品。

标签: c++ exception try-catch


【解决方案1】:

不要“吃掉”访问违规;那就是卑鄙的疯狂所在。

在我看来,您正在尝试取消对空指针的引用。也许干脆不要那样做!

if (!resFilter) {
   // do something else; e.g. did you fail to initialise the library properly?
   throw "Yikes!";
}

// OK; pointer is not NULL at least: let's go!
sts = resFilter->initialize(m_JPEG2000File);

现在,如果您从 that 收到访问冲突,则该库存在严重错误,您应该立即停止使用它,除非有可用的修复或补丁。

由于您使用的是 Windows,如果您只想检测问题以记录日志,您可以使用Visual Studio's non-standard __try/__catch construct,但请务必在记录问题后立即终止进程,因为您的进程(尤其是图书馆的状态)将是不稳定的,之后你对它做的任何事情都没有任何意义!

__try  { 
    sts = resFilter->initialize(m_JPEG2000File);
} 
__except(
   GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
   ? EXCEPTION_EXECUTE_HANDLER
   : EXCEPTION_CONTINUE_SEARCH) { 
    std::cerr << "OMG!\n";
    exit(-1);
}

【讨论】:

  • 我检查了所有我能到达的指针,没有一个是 NULL。此外,如果我加载另一个文件,一切正常。所以我确信异常是在第 3 方大会内部引发的。我正在打开一个文件夹中的所有文件,如果有问题我只想跳过它并进入下一个。这就是为什么我想“吃掉”异常而不折叠整个应用程序的原因。
  • @Ben:“如果一个有问题,我只想跳过它并进入下一个” 这真的不太可能顺利。如果您要“跳过”所有事物的 NULL 指针取消引用,那么您应该在此之后考虑该过程不稳定。你知道在这一点上,至少有一个关键的先决条件不成立。在那之后发生的任何事情都无法依赖,因此当您可能只是自己造成负载时,继续进行“下一个”问题是毫无意义的。 :)
  • 感谢您的提醒!我了解风险,但我无能为力。它在第 3 方 dll 中,我无法修复它。我正在考虑捕获异常,清理所有资源并重新开始一切,然后再进行下一个,这对我来说应该是安全且足够好的。感谢 Adriano Repetti,__try 成功了!
  • @Ben:这不是“风险”:这完全没有意义。从字面上看,您正在击败做您想做的事情的对象。正如我已经解释过的,它安全,而且不够对你来说不够好!
  • @Ben 我完全同意 LRiO!您自己的数据可能已完全损坏(当它访问 0x00 时您会看到崩溃,但它可能首先破坏您的一半代码段)。即使他们不是......进程处于未定义状态。它稍后可能会崩溃,您将尝试调试完全有效的代码。不要做。如果存在这种情况,则为您必须处理的每个文件运行一个外部进程,并检查其返回代码以查看是否可以加载该 DLL。如果安全,则将其加载到您自己的应用中。
【解决方案2】:

__try 和 __except 可以捕获这个异常。感谢@Adriano Repetti!

这是一篇关于它的好帖子: C++, __try and try/catch/finally

【讨论】:

  • __try, __except 等不是 C++。在 C++ 中不可能捕捉到这样的“异常”。事实上,从 C++ 的角度来看,这里根本没有例外。代码被简单地破坏并产生未定义的行为。尝试使用 __try__except 在“第三方 dll”中“抑制”此类错误是完全没有意义的。
  • 我不得不提...本,不要那样做。说真的!
  • 伙计们,我发现了这个异常,所以我有机会记录错误,我仍然会终止这个过程。我有一个外部 C# 进程来循环数据,它每次都会从头开始一个新的 C++ 进程,因此它将是一个新的完整实例。所以它对我有用。抱歉没有说得更清楚,感谢您的意见!
猜你喜欢
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多