如何在退出时在CorExitProcess中调试访问冲突0xC0000005?

flo*_*ele 6 .net c++ debugging access-violation

我们的应用程序(用C++,VS 2010项目编写)在Windows 8之前的所有操作系统上运行良好(现在仍然如此).但是,在Windows 8上,当有序退出应用程序时,会发生访问冲突:

mfc100.dll!_DllMain@12()    <<< Crash here
mfc100.dll!__CRT_INIT@12()  
mfc100.dll!__DllMainCRTStartup@12() 
ntdll.dll!_LdrxCallInitRoutine@16() 
ntdll.dll!LdrpCallInitRoutine() 
ntdll.dll!LdrShutdownProcess()  
ntdll.dll!RtlExitUserProcess()  
kernel32.dll!_ExitProcessImplementation@4() 
mscoreei.dll!RuntimeDesc::ShutdownAllActiveRuntimes(unsigned int,class RuntimeDesc *,enum RuntimeDesc::ShutdownCompatMode)  
mscoreei.dll!_CorExitProcess@4()    
mscoree.dll!_ShellShim_CorExitProcess@4()   
msvcr100d.dll!__crtCorExitProcess(int status) line693   C
msvcr100d.dll!__crtExitProcess(int status) line 699 C
msvcr100d.dll!doexit(int code, int quick, int retcaller) line 621   C
msvcr100d.dll!exit(int code) Zeile 393  C
my.exe!__tmainCRTStartup() Zeile 568    C
my.exe!WinMainCRTStartup() Zeile 371    C
kernel32.dll!@BaseThreadInitThunk@12()  
ntdll.dll!__RtlUserThreadStart()    
ntdll.dll!__RtlUserThreadStart@8()  
Run Code Online (Sandbox Code Playgroud)

在MSDN论坛主题中,建议GC.Collect()在退出之前运行,但是在退出之前不久我就不能对这样的调用产生任何影响.

关于如何调试问题,我有点不知所措.据我所知,CorExitProcess负责清理应用程序的托管资源.那么这可能是托管组件中的错误吗?
或者是否更有可能某些函数指针_DllMain被覆盖/损坏?如果是这样,我如何在相关地址设置数据断点?有一篇文章解释了如何调试类似的问题,但是他在自己的DLL中遇到了这个问题,所以他实际上可以找到问题的确切来源,而我却无法解决.

有什么建议?

编辑:其他信息,windbg !analyze -v:

FAULTING_IP: 
mfc100+258e6c
64298e6c 8b4654          mov     eax,dword ptr [esi+54h]

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 64298e6c (mfc100+0x00258e6c)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 53f21f0c
Attempt to read from address 53f21f0c

CONTEXT:  00000000 -- (.cxr 0x0;r)
eax=53f21eb8 ebx=00000000 ecx=64187d2d edx=7fcde000 esi=53f21eb8 edi=00000001
eip=64298e6c esp=00c3f1b8 ebp=00c3f2ec iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206
mfc100+0x258e6c:
64298e6c 8b4654          mov     eax,dword ptr [esi+54h] ds:0023:53f21f0c=????????

FAULTING_THREAD:  00000520

DEFAULT_BUCKET_ID:  WRONG_SYMBOLS

PROCESS_NAME:  ww.exe

ADDITIONAL_DEBUG_TEXT:  
You can run '.symfix; .reload' to try to fix the symbol path and load symbols.

MODULE_NAME: mfc100

FAULTING_MODULE: 77bc0000 ntdll

DEBUG_FLR_IMAGE_TIMESTAMP:  4d5f29b8

ERROR_CODE: (NTSTATUS) 0xc0000005 - Die Anweisung in 0x%08lx verweist auf Speicher 0x%08lx. Der Vorgang %s konnte nicht im Speicher durchgef hrt werden.

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - Die Anweisung in 0x%08lx verweist auf Speicher 0x%08lx. Der Vorgang %s konnte nicht im Speicher durchgef hrt werden.

EXCEPTION_PARAMETER1:  00000000

EXCEPTION_PARAMETER2:  53f21f0c

READ_ADDRESS:  53f21f0c 

FOLLOWUP_IP: 
mfc100+258e6c
64298e6c 8b4654          mov     eax,dword ptr [esi+54h]

APP:  ww.exe

ANALYSIS_VERSION: 6.3.9600.17029 (debuggers(dbg).140219-1702) x86fre

MANAGED_STACK: !dumpstack -EE
OS Thread Id: 0x520 (0)
Current frame: 
ChildEBP RetAddr  Caller, Callee

PRIMARY_PROBLEM_CLASS:  WRONG_SYMBOLS

BUGCHECK_STR:  APPLICATION_FAULT_WRONG_SYMBOLS

LAST_CONTROL_TRANSFER:  from 6429da08 to 64298e6c

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.
00c3f2ec 6429da08 64040000 00000000 00000001 mfc100+0x258e6c
00c3f330 6429dac7 64040000 00c3f35c 77be077a mfc100+0x25da08
00c3f33c 77be077a 64040000 00000000 00000001 mfc100+0x25dac7
00c3f35c 77be07f0 6429daa9 64040000 00000000 ntdll!RtlAddMandatoryAce+0x14e
00c3f3a4 77bfa529 6429daa9 64040000 00000000 ntdll!RtlAddMandatoryAce+0x1c4
00c3f49c 77bfa40e 00000000 00000000 6f2d4890 ntdll!RtlExitUserProcess+0x1e7
00c3f4b0 76ff4231 00000000 77e8f3b0 ffffffff ntdll!RtlExitUserProcess+0xcc
00c3f4c4 6f8b3712 00000000 bd3cbe8b 01f1c054 KERNEL32!ExitProcess+0x15
00c3f74c 6f8c19a2 00000001 00c3f76c 6f1686ad mscoreei!GetFileVersion+0x1835
00c3f758 6f1686ad 00000000 77bdab85 6f8a0000 mscoreei!CorExitProcess+0x27
00c3f76c 70737954 00000000 00c3f784 7073798d mscoree!CorExitProcess+0x94
00c3f778 7073798d 00000000 00c3f7c8 70737ab0 MSVCR100!_query_new_mode+0x159
00c3f784 70737ab0 00000000 a2b843a9 00375f5c MSVCR100!_query_new_mode+0x192
00c3f7c8 70737b1d 00000000 00000000 00000000 MSVCR100!_query_new_mode+0x2b5
00c3f7dc 003274ab 00000000 d1ef1931 00000000 MSVCR100!exit+0x11
00c3f864 76ff173e 7fcdf000 00c3f8b4 77c16911 ww!_enc$textbss$begin+0x64ab
00c3f870 77c16911 7fcdf000 a613e810 00000000 KERNEL32!BaseThreadInitThunk+0x12
00c3f8b4 77c168bd ffffffff 77c8560a 00000000 ntdll!LdrInitializeThunk+0x1f0
00c3f8c4 00000000 003275da 7fcdf000 00000000 ntdll!LdrInitializeThunk+0x19c


STACK_COMMAND:  .cxr 0x0 ; kb

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  mfc100+258e6c

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  mfc100.dll

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  WRONG_SYMBOLS_c0000005_mfc100.dll!Unknown

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:wrong_symbols_c0000005_mfc100.dll!unknown

FAILURE_ID_HASH:  {9e516b68-081f-78d6-cf23-b42f2b3cb573}

Followup: MachineOwner
---------
Run Code Online (Sandbox Code Playgroud)

发生崩溃的屏幕截图: 源代码

Rog*_*and 5

正如评论中所讨论的,我们的类似问题是我们有一个本机 C++ 应用程序,它与作为 COM 服务器运行的托管 C# 应用程序进行通信。为了允许托管组件与 C++ 应用程序通信,事件接收器被公开为来自本机端的简单 ATL COM 接口,在 .NET 端自动封装在运行时可调用包装器中

应用程序关闭时的访问冲突 - 除了在事件日志中并不总是可见 - 是由于 RCWRelease()在它被垃圾收集之前没有调用我们的 ATL COM 接口这一事实。由于这是在 .NET 运行时关闭时发生的,也就是本机运行时关闭之后,它试图回调到死代码中。

我们的解决方案是在 .NET 端公开一个“关闭”方法,该方法处理所有通信对象,然后调用:

GC.Collect();
GC.WaitForPendingFinalizers();
Run Code Online (Sandbox Code Playgroud)

好的,我知道这可能不能完全反映您的问题,但是找出导致问题的原因的途径是使用Managed Debugging Assistants,特别是reportAvOnCOMRelease

我们通过注册表项激活 MDA 并通过调试器运行本机应用程序以查看附加输出,这些输出标识了被保持太长时间的 COM 接口。可能作为第一步,激活所有 MDA 选项以从崩溃中收集尽可能多的信息是明智的。


flo*_*ele 4

我尝试使用数据断点进行调试,但这并没有多大帮助。我可以看到在某些时候正在访问的数据被覆盖,但在包含我自己的代码的调用堆栈中并没有发生这种情况。

所以我采取了一种更简单的方法,开始删除部分程序,直到错误消失。在大型应用程序中,可能很难在不破坏其他部分的情况下删除某些部分,但我能够缩小问题的根源。

基本上,在删除对 的某个调用后,问题就不再发生了FreeLibrary。经过进一步调查,发现此调用发生在 期间DllMain这是不允许的

入口点函数应该只执行简单的初始化或终止任务。它不能调用 LoadLibrary 或 LoadLibraryEx 函数(或调用这些函数的函数),因为这可能会在 DLL 加载顺序中创建依赖循环。这可能会导致 DLL 在系统执行其初始化代码之前被使用。同样,入口点函数在进程终止期间不得调用 FreeLibrary 函数(或调用 FreeLibrary 的函数),因为这可能会导致系统执行其终止代码后使用 DLL

在另一个 SO 问题中,一位用户显然注意到自 Windows 8 以来在这方面发生的变化,这可以解释为什么错误只发生在这个版本的 Windows 上。

我们现在将更改我们的应用程序,以便FreeLibrary在不同的时间点调用它。