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

时间:2018-04-17 13:38:43

标签: vb.net windbg heap-corruption first-chance-exception adplus

后续问题:"在调查崩溃时,我是否应该仅调查第二次机会异常?当我还需要调查第一次机会异常转储时会出现什么情况?"

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

编辑:以下是示例文章,但还有很多其他内容:

What is a First Chance Exception?

  

"对于没有异常处理的代码,调试器将收到一个   第二次机会异常通知,并将以未处理的方式停止   例外。 "

Program crashes, but Debug Diag says it's a first chance exception, is that correct?

  

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

我的应用程序重新启动或崩溃(事件查看器中没有错误)但在重新启动之前出现间歇性问题,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]

错误是关于堆损坏和无效指针,我还在研究。我是一个关于堆和mallocs的完整新手,我刚学会使用WinDbg进行调试。我只是想知道,如果不是我的优先考虑并且不能解决我的问题,我是否会浪费时间学习内存分配。 (当然了解堆是一件好事,但解决主要问题是首要任务)

我对adplus配置文件充满信心,我确信它会在所有第二次机会异常时生成完整转储。我在示例应用程序上尝试过它。

应用程序没有崩溃,它只是意外地和间歇性地重启而没有事件查看器错误。当使用特定服务时,可以间歇性地重新创建它。

如果转储文件不是导致问题的原因,我可能会想到这一点:

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

PS:很抱歉,如果我没有指定一些详细信息和代码示例等,因为它是保密的。在不影响公司政策的情况下,我尽力解释这个问题。

预先谢谢你!

1 个答案:

答案 0 :(得分:1)

这个MSDN article about exception dispatching解释了这个过程:

  

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

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

在第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而崩溃,但真正的原因是之前的异常。但是,这些案例通常很容易识别,而无需查看第一次机会异常。

案例2:

异常具有很高的开销,即它们会花费CPU周期,从而降低性能。如果你有很多第一次机会异常,你可能想要摆脱它们。