我最近将高度线程化,非托管的Win32 C ++控制台应用程序(MediaServer.exe)转换为非托管的Win32 DLL(MediaServer.dll)。我在一个单独的非托管Win32控制台应用程序中托管和调试这个DLL,并且所有内容都编译并运行,但是大约一分钟之后,我会在一个没有意义的地方随机崩溃,显然是一个腐败的调用堆。这些崩溃发生在各种不同的地方,并且在某些随机的时间发生:但通用性是(显然已损坏的)调用堆栈总是在其上的某个地方具有各种libxml2.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()
或者如果你很幸运,就像这样:
ntdll.dll!_RtlpWaitOnCriticalSection@8() + 0x99 bytes
ntdll.dll!_RtlEnterCriticalSection@4() - 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++
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
崩溃本身通常会说“MediaServerConsole.exe中0x77cd2239(ntdll.dll)的未处理异常:0xC000005:访问冲突写入位置0x00000014。”
毋庸置疑,当我将模块编译为控制台应用程序时,这种情况并未发生。
在将项目转换为DLL时,我可能忽略了什么?这不是我以前做过的事情,所以如果我忽略了一些明显的东西,我不会感到惊讶。任何帮助表示赞赏。
答案 0 :(得分: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中移动初始化代码,这将确保在主进程线程上分配所有内存,类似于应用程序作为单个可执行文件的工作方式。
答案 1 :(得分:0)
我将另一个答案留作“接受”的答案,但是人们知道问题的关键部分是我在错误的线程上初始化libxml2这一事实可能会有所帮助。具体来说,在进行任何调用之前,需要在主线程上调用xmlInitParser()。对我来说,这意味着:
MediaServer::MediaServer() : mProvidePolicyThread (0),
mProcessCommandsThread(0),
mAcceptMemberThread (0)
{
xmlInitParser();
}
同样,退出时需要调用xmlCleanupParser():
MediaServer::~MediaServer()
{
xmlCleanupParser();
}
这里记录了所有内容:http://xmlsoft.org/threads.html