2011-07-22 58 views
1

我最近将高度线程化的非托管Win32 C++控制台应用程序(MediaServer.exe)转换为非托管Win32 DLL(MediaServer.dll)。我在一个单独的非托管Win32控制台应用程序中托管和调试此DLL,并且所有内容都会编译并运行,但一分钟左右后,我会随机发生崩溃,在一个毫无意义的地方发生,并显示一个显然已损坏的调用叠加。这些崩溃发生在各种不同的地方,并且在某些随机时间发生:但通用性是(显然已损坏的)调用堆栈总是在其上某处存在各种libxml2.dll函数,例如,崩溃可能在看起来像一条线像这样:将C++/Win32控制台应用程序转换为DLL后崩溃

xmlDoc * document = xmlReadMemory(message.c_str(), message.length(), "noname.xml", NULL, 0); 

或者这样:

xmlBufferPtr buffer = xmlBufferCreate(); 

且调用栈可能是这样的:

feeefeee() 
libxml2.dll!000eeec9() 
[Frames below may be incorrect and/or missing, no symbols loaded for libxml2.dll] 
libxml2.dll!00131714() 
libxml2.dll!001466b6() 
libxml2.dll!00146bf9() 
libxml2.dll!00146c3c() 
libxml2.dll!0018419e() 

或者,如果你是幸运的,就像这样:

[email protected]() + 0x99 bytes 
[email protected]() - 0x15658 bytes 
libxml2.dll!1004dc6d() 
[Frames below may be incorrect and/or missing, no symbols loaded for libxml2.dll] 
libxml2.dll!10012034() 
libxml2.dll!1004b7f7() 
libxml2.dll!1003904c() 
libxml2.dll!100393a9() 
libxml2.dll!10024621() 
libxml2.dll!10036e8f() 
MediaServer.dll!Controller::parse(std::basic_string<char,std::char_traits<char>,std::allocator<char> > message) Line 145 + 0x20 bytes C++ 
MediaServer.dll!Controller::receiveCommands() Line 90 + 0x25 bytes C++ 
MediaServer.dll!MediaServer::processCommands() Line 88 + 0xb bytes C++ 
MediaServer.dll!MediaServer::processCommandsFunction(void * mediaServerInstance) Line 450 + 0x8 bytes C++ 
MediaServer.dll!CustomThread::callThreadFunction() Line 79 + 0x11 bytes C++ 
MediaServer.dll!threadFunctionCallback(void * threadInstance) Line 10 + 0x8 bytes C++ 
[email protected]@12() + 0x12 bytes  
[email protected]() + 0x27 bytes 
[email protected]() + 0x1b bytes  

崩溃本身通常会这样说: “在0x77cd2239(ntdll.dll中)在MediaServerConsole.exe未处理的异常:0xC000005:访问冲突写入位置0x00000014。”

不用说,当我编译模块作为控制台应用程序时,没有发生这种情况。

将项目转换为DLL时,可能忽略了什么?这不是我以前做过的事情,所以如果有什么明显的我忽略了,我不会感到惊讶。任何帮助表示赞赏。

+0

您是否尝试过在运行任何[本主题]中的建议程序(http://stackoverflow.com/questions/413477/is-there-a-good-valgrind-substitute-for-windows)? Purify,Insure ++等可以帮助您追踪程序中的细微错误。 –

+0

还没有,但我现在正在下载Visual Leak Detector,看它是否可以确定任何事物。 (推测它不在Purify或Insure ++的同一级别,但它是免费的......) –

+0

什么导致了崩溃?访问违规?我假设是,因为释放的堆标有0xFEEFEEE。这听起来像你的堆栈溢出或你的堆已损坏。此外,您可以检查DLL链接的CRT(静态/动态,调试/发布) –

回答

1

我会说你正在初始化DLL_THREAD_ATTACH内存而不是DLL_PROCESS_ATTACH。这种情况会导致你使用已经在另一个线程中分配的指针或内存,而不是正在执行的线程。

另一件事是检查你的加载你的DLL的依赖关系。

让我解释一下。当您的DLL使用loadlibrary加载时,CRT执行全局内存分配。这是为了初始化所有全局变量,范围从C初始类型,默认情况下它们初始化为零。然后它为struct/classes分配内存,并在必要时调用其构造函数。

然后,CRT使用DLL_PROCESS_ATTACH调用您的DLLMain方法来告诉您的进程已加载的DLL。对于该进程中的每个线程,CRT会使用DLL_THREAD_ATTACH调用您的DLL。

你说过这些空了,然后你打电话给你导出的C函数。虽然我可以看到你会被抓到关键部分。这告诉我,您的全局分配变量和您的线程在Start()中分配内存时发生死锁情况。

我建议您在Process_Attached内移动您的初始化代码,这将确保您的所有内存都分配在主进程线程上,类似于应用程序如何作为单个可执行文件运行。

+0

这是一件好事,但我的DllMain(正如MS显然推荐的那样)是一个空的存根。我目前只在一个Start()函数中分配内存,声明为:extern“C”__declspec(dllexport)int Start(){/ * Stuff * /} –

+0

是的,但CRT在不同的线程上分配全局内存。这就是我所掌握的。看起来当两个线程试图访问CriticalSection时,你会遇到死锁。 – Chad

+0

很可能我在这里错过了一些东西,然后:-)。如果我没有初始化DllMain中的任何东西,我如何确保我在Start()中初始化的内容在正确的线程上正确初始化? –

0

我会留下对方的回答是“接受”的答案,但它可能有助于人们了解这个问题的一个关键部分是事实,我是错误的线程上初始化的libxml2。具体来说,在进行任何调用之前,您需要在主线程上调用xmlInitParser()。对我来说,这意味着:

MediaServer::MediaServer() : mProvidePolicyThread (0), 
         mProcessCommandsThread(0), 
         mAcceptMemberThread (0) 
{ 
    xmlInitParser(); 
} 

,同样,你需要调用xmlCleanupParser()当您退出:

MediaServer::~MediaServer() 
{ 
    xmlCleanupParser(); 
} 

这是这里的所有记载:http://xmlsoft.org/threads.html

相关问题