使用托管c++库时出现WS2_32.dll_unloaded异常
WS2_32.dll_unloaded exception when using managed C++ library
有人知道下面的崩溃意味着什么或如何调试它吗?
故障应用程序名称:MyServer.exe,版本:0.0.0.0,时间戳:0x53d885f1
故障模块名称:WS2_32.dll_unloaded,版本:0.0.0.0,时间戳:0x4ce7ca25
异常码:0xc0000005
故障偏移量:0x000007fefe67a0af
故障进程id: 0xcbc
应用程序启动时间:0x01cfabbc216f52c2
故障应用程序路径:[path]/MyServer.exe
故障模块路径:WS2_32.dll
报告Id: 61efadce-17af-11e4-8301-001517d9c80a
当我将我的exe(非托管c++)与托管c++ dll(通过dllexport暴露)链接时,会发生这种情况。从windbg来看,似乎崩溃发生在加载所有模块之后,甚至在它到达main之前:
(51d4.5 .5e50):访问违规-代码c0000005(第一次机会)在任何异常处理之前报告第一次机会异常。这种异常是可以预料和处理的。+ 0 x1a0af:000007fe fe67a0af ?? ???
0:000> kP
Child-SP RetAddr Call Site
00000000
0020dc80 00000000 002a2700 <Unloaded_WS2_32.dll>+0x1a0af
00000000
0020dc88 00000000 002a2701 0x2a2700
00000000
0020dc90 00000000 ' 00000000 0x2a2701
托管c++ dll是一个DNS库,它最终调用下面的WS2_32.dll。
奇怪的是,另一个使用相同的托管c++ dll的exe工作得很好,我没有看到源/头文件之间有任何明显的差异,这会导致这种不同的行为。如果我注释掉(1)引用这个托管dll的代码,或者(2)我的exe中除了引用托管dll的代码之外的所有其他代码,那么崩溃也不会发生。(2)工作的事实告诉我,至少所有的dll依赖项都应该在工作目录中。
这只发生在Windows Server 2008 R2上。我使用的是。net 4.5。
谁有什么建议?
我遇到过一个类似的问题,涉及到一个本机应用程序,它使用了许多dll,其中一个是托管的。应用程序无法访问主程序的事实表明DLL的DllMain返回FALSE。然而,我不知道是哪一个,尽管事件查看器中的日志显示了与op提供的类似的错误信息。对我来说幸运的是,应用程序仅在新构建的pc上失败。为尝试调试问题而执行的操作:
- 使用加载器快照来跟踪DLL加载过程。结合WinDbg,它给出了哪个DLL失败的指示,因为一堆未初始化的DLL包括除了一个初始化器运行之外的所有DLL。它没有显示每个DLL的dlmain的实际返回值。
- 使用Dependency Walker的分析选项来跟踪dllmain的返回值。然而,这并没有取得成果。
- 在两台机器上使用ProcMon捕获启动并比较跟踪。在检查注册表项
HKLMSoftwareMicrosoftSQMClientWindowsCEIPEnable
后,这是更富有成效的,并且在两者之间显示出不同的行为。在工作情况下,CEIPEnable
为0。在失败的情况下,CEIPEnable
为1。这就是nop提到的Windows客户体验改进计划。禁用此选项允许应用程序在故障机器上启动。 - 使用AppVerifier来捕获那些在DllMain中调用
WSAStartup
的dll(当在调试器下运行时)。这确实标记了可疑的DLL(以及其他DLL)。此行为与Richard所指出的MSDN的建议相反。
进一步观察:
- 如果我在正常的机器上启用了CEIP,应用程序仍然可以成功启动。因此,一定是其他因素导致了故障。
- 微软日本有一篇关于这个问题的文章,其中禁用CEIP被列为解决方案。链接的文章是日文的,但谷歌可以翻译。
- 托管的DLL似乎不是问题。
我希望有人觉得这个答案有用。如果没有nop的答案,我就解决不了我的问题。
我最近遇到了完全相同的症状(和相同的调用堆栈),但是没有其他DLL干扰ws2_32.dll,所以我只是把这个放在这里以防其他人有同样的问题:在我的情况下,罪魁祸首是Windows的客户体验改进程序,如果启用,使我的应用程序崩溃。把它关掉就没事了。
我对这种行为没有深入的解释,只是你在函数名中看到的"Sqm"与此服务有关,当客户体验改进程序被禁用时,ws2_32.dll内将采用不同的代码路径(有一个函数检查Sqm选项在WSAStartup期间调用)。
经过调试我找到了原因。我能够将问题减少到两个API调用:
void __cdecl main(int argc, __in_ecount(argc) char* argv[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
HRESULT hr = TS_STATUS_OK;
/***** A *****/
hr = InitializeDllA();
ASSERT(SUCCEEDED(hr));
/***** B *****/
hr = InitializeDllB();
ASSERT(SUCCEEDED(hr));
}
两个dll都依赖于WS2_32.dll但是发生的事情是,在A的dlmain()中,有一个对WSAStartup()的调用,它最终卸载了WS2_32.dll。在模块加载/卸载时设置断点后,来自WinDBG的堆栈跟踪确认了这一点:
0:000> k
Child-SP RetAddr Call Site
00000000`001ae0c8 00000000`771f2773 ntdll!ZwUnmapViewOfSection+0xa
[e:obj.amd64freminkernelntdlldaytonaobjfreamd64usrstubs.asm @ 484]
00000000`001ae0d0 00000000`771f3b5a ntdll!LdrpUnloadDll+0x3c6 [d:win7sp1_gdrminkernelntdllldrapi.c @ 1672]
00000000`001ae1f0 000007fe`fd822dd5 ntdll!LdrUnloadDll+0x4a [d:win7sp1_gdrminkernelntdllldrapi.c @ 1743]
00000000`001ae220 000007fe`fee5a0af KERNELBASE!FreeLibrary+0x1d [d:win7sp1_gdrminkernelkernelbasemodule.c @ 1193]
00000000`001ae250 000007fe`fee54a68 WS2_32!Ws2SqmGetFileVersionInfo+0x12f [d:w7rtmminiosocketswinsock2sqmlibws2sqm.c @ 308]
00000000`001ae2c0 000007fe`fee473df WS2_32!Ws2SqmInit+0xd678
00000000`001ae510 000007fe`d7c01042 WS2_32!WSAStartup+0x2fd [d:w7rtmminiosocketswinsock2ws2_32srcstartup.cpp @ 301]
有一篇MSDN文章是关于这个:WSAStartup函数的。
WSAStartup函数通常会导致特定于协议的helper正在加载dll。因此,WSAStartup函数不应该是从应用程序DLL中的DllMain函数调用。这可以可能导致死锁。有关更多信息,请参阅DLL主要功能。
这解释了为什么程序在进入main()
之前崩溃,因为崩溃发生在DLL加载期间。
- 挂起和取消挂起一个文件DLL
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 导入库可以跨dll版本工作吗
- 从C++dll访问C#中的一行主要参数
- 链接到自行创建的dll失败
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- C++:将外部库链接到dll库
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 不同的Visual Studio版本中缺少.dll
- 从DLL中删除类的实例
- 如何包装第三方DLL在R中使用
- 使用c#访问c++dll中带有char*参数的函数时发生AccessViolationException
- 系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Python ctypes:不会按预期加载 dll
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL