0

后续问题: “在调查崩溃时,我应该只调查第二次机会异常吗?在哪些情况下我还需要调查第一次机会异常转储?”

我的问题有点宽泛,但我很好奇真正的答案是什么。我读过很多文章说第一次机会异常不太可能导致应用程序崩溃。这是导致它的第二次机会异常。一个简单的谷歌搜索并不能直接回答我的问题。

编辑:这里是示例文章,但还有更多:

什么是第一次机会例外?

“对于没有异常处理的代码,调试器将收到第二次机会异常通知,并会因未处理的异常而停止。”

程序崩溃,但 Debug Diag 说这是第一次机会异常,对吗?

当然,根据定义,只有第二次机会异常会导致代码崩溃,即代码未处理的异常?

我遇到了一个间歇性问题,我的应用程序重新启动或崩溃(事件查看器中没有错误),但在重新启动之前,Adplus 会生成一些第一次机会 AccessViolation 异常。没有第二次机会例外。

下面是 WinDbg.exe 上 FULLDUMP_FirstChance_av_AccessViolation 的片段:

PROBLEM_CLASSES: 
HEAP_CORRUPTION
    Tid    [0x16e8]
    Frame  [0x02]: ntdll!RtlAllocateHeap
HEAP_CORRUPTION
    Tid    [0x16e8]
    Frame  [0x02]: ntdll!RtlAllocateHeap
INVALID_POINTER_READ
    Tid    [0x16e8]
    Frame  [0x00]: ntdll!ExpInterlockedPopEntrySListFault
NOSOS
    Tid    [0x16e8]
BUGCHECK_STR:  HEAP_CORRUPTION_HEAP_CORRUPTION_INVALID_POINTER_READ_NOSOS

下面的示例调用堆栈:

# ChildEBP RetAddr  Args to Child              
00 085aec28 7c91020e 00000007 00c407d8 00c40000 ntdll!ExpInterlockedPopEntrySListFault (FPO: [0,2,0])
01 085aec58 7c91019b 00c407d8 00000030 00000000 ntdll!RtlpAllocateFromHeapLookaside+0x1d (FPO: [Non-Fpo])
02 085aee84 78134d83 00c40000 00000000 00000030 ntdll!RtlAllocateHeap+0x1c2 (FPO: [Non-Fpo])
03 085aeea4 78160e30 00000030 0000002f 085aeecc msvcr80!malloc(unsigned int size = 0x30)+0x7a (FPO: [1,0,0]) (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163]
04 085aeebc 7c4221b3 00000030 00000003 7c422f20 msvcr80!operator new(unsigned int size = 0x30)+0x1d (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\new.cpp @ 59]
05 085aeed4 7c423315 00000030 00000000 ae218f51 msvcp80!std::_Allocate<char>(unsigned int _Count = 0x30, char * __formal = 0x00000000 "")+0x15 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\xmemory @ 44]
06 085aef0c 7c4233c4 0000002a 00000000 085af028 msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Copy(unsigned int _Newsize = 0x2a, unsigned int _Oldlen = 0)+0x55 (FPO: [Non-Fpo]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 2020]
07 085aef20 7c423779 0000002a 00000000 085af200 msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow(unsigned int _Newsize = 0x2a, bool _Trim = false)+0x22 (FPO: [2,0,0]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 2050]
08 085aef3c 7c425e55 0000002a 00000000 0000002a msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * _Right = 0x0000002a, unsigned int _Roff = 0, unsigned int _Count = 0x2a)+0x58 (FPO: [Non-Fpo]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 969]
09 085aef4c 60baed1e 085af028 ae262fd2 085af1a4 msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * _Right = 0x085af028 " S1 S1 Card number:    ************8706  
")+0xd (FPO: [1,0,0]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 956]
0a 085af1a4 7c802662 00000100 00000000 00000000 aipoptrv19!DllUnregisterServer+0x1f15e
0b 085af234 7c42317a 00000000 00000000 0000000f kernel32!WaitForSingleObject+0x12 (FPO: [Non-Fpo])
0c 085af274 60bc1fd8 60baa1cb 0865d680 0000001c msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(void)+0x11 (FPO: [0,0,4]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 576]
0d 085af278 60baa1cb 0865d680 0000001c 00000002 aipoptrv19!DllUnregisterServer+0x32418
0e 085af2e4 60bb227c 00000001 085af420 0865d648 aipoptrv19!DllUnregisterServer+0x1a60b
0f 085af34c 7c425e45 085af404 00000000 ffffffff aipoptrv19!DllUnregisterServer+0x226bc
10 085af35c 60b97724 72506f44 69746e69 0000676e msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * _Right = 0x72506f44)+0xd (FPO: [1,0,0]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 1044]
11 085af45c 78261414 00000002 403110f4 7824f516 aipoptrv19!DllUnregisterServer+0x7b64
12 085af468 7824f516 fffffffe 781f2c2e 0000001c mfc80!_AfxDispatchCall(<function> * __formal = 0x40b59c84, void * __formal = 0x085af6b8, unsigned int __formal = 0x85a0003)+0x10 (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\olecall.cpp @ 40]
13 085af470 781f2c2e 0000001c 7824f49b 00000008 mfc80!CCmdTarget::CallMemberFunc(struct AFX_DISPMAP_ENTRY * pEntry = 0x6d756e20, unsigned short wFlags = 0x6562, struct tagVARIANT * pvarResult = 0x20202020 Empty, struct tagDISPPARAMS * pDispParams = 0x2a2a2a2a, unsigned int * puArgErr = 0x2a2a2a2a)+0x1ad (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\oledisp1.cpp @ 1064]

该错误与我仍在研究的堆损坏和无效指针有关。我是堆和 malloc 的新手,我刚刚学会了使用 WinDbg 进行调试。我只是想知道当这不是我的优先事项并且不会真正解决我的问题时,我是否在浪费时间学习内存分配。(当然了解堆是一件好事,但解决主要问题是重中之重)

我对我的 adplus 配置文件很有信心,我确信它会在所有第二次机会异常中生成完整的转储。我在示例应用程序上进行了尝试。

该应用程序不会崩溃,它只是在没有事件查看器错误的情况下意外和间歇性地重新启动。它可以在使用特定服务时间歇性地重新创建。

如果转储文件不是问题的真正原因,这是我可能的想法:

  • 其他进程(未附加在我的 adplus 上)导致重新启动。
  • 第二次机会异常完全转储只是没有生成。
  • 其他(有什么想法吗?)

PS:对不起,如果我没有指定一些细节和代码示例等,因为它是机密的。我在不影响公司政策的情况下尽力解释了这个问题。

提前谢谢!

4

1 回答 1

1

这篇关于异常调度的 MSDN 文章解释了该过程:

当用户模式代码发生异常时,系统使用以下搜索顺序查找异常处理程序:

  1. 如果进程正在调试,系统会通知调试器。有关详细信息,请参阅调试器异常处理。
  2. 如果进程没有被调试,或者关联的调试器没有处理异常,系统会尝试通过搜索发生异常的线程的堆栈帧来定位基于帧的异常处理程序。系统先查找当前栈帧,然后以相反的顺序查找前面的栈帧。
  3. 如果找不到基于帧的处理程序,或者没有基于帧的处理程序处理异常,但正在调试进程,则系统会第二次通知调试器。
  4. 如果进程没有被调试,或者关联的调试器没有处理异常,系统会根据异常类型提供默认处理。对于大多数例外情况,默认操作是调用 ExitProcess 函数。

在第 1 步中,异常被称为第一次机会异常,因为这是任何人都可以捕获并处理异常的第一次机会。

在第 3 步中,同样的异常称为第二次机会异常,因为这是第二次,调试器有机会捕获并处理异常。

只有当进程继续到第 4 步时,程序才会崩溃或退出。因此,是的,只有第二次机会异常才能使进程崩溃。

非托管的第一次机会异常会导致崩溃/重启吗?

不,见前。

在调查崩溃时,我应该只调查第二次机会异常吗?

基本上是的。这就是每个人 (>90%) 在分析崩溃时所做的事情。

在哪些情况下我还需要调查第一次机会异常转储?

情况1:

第二次机会异常可能是先前第一次机会异常的结果。由于第一次机会异常,一个值可能未初始化并导致不同的第二次机会异常。

这种情况的示例代码:

SomeObject o = null;
try {
    throw new Exception("First chance"); // consider this in some method
    o = new SomeObject();
}
catch (Exception)
{
    // make sure that the exception does not become a second chance exception
}
o.DoSomething(); // causes NullReferenceException first chance and second chance if uncaught

应用程序由于 NullReferenceException 而崩溃,但真正的原因是之前的异常。但是,这种情况通常很容易识别,而无需查看第一次机会异常。

案例二:

异常有很高的开销,即它们消耗 CPU 周期和性能。如果你真的有很多第一次机会例外,你可能想摆脱它们。

于 2018-04-18T19:52:01.197 回答