如何在应用程序退出时诊断 comptr 版本中的异常
Posted
技术标签:
【中文标题】如何在应用程序退出时诊断 comptr 版本中的异常【英文标题】:how to diagnose exception in comptr release on application exit 【发布时间】:2013-12-05 14:53:02 【问题描述】:我的应用程序在应用程序退出时出现异常。当调用 CoUnintialize 时,Callstack 显示异常来自 CComPtr::release。
> ieframe.dll!ATL::CComPtr<IWebBrowser2>::Release() + 0x5b bytes
ieframe.dll!CConnectionPoint::UnadviseAll() + 0x131d0 bytes
ieframe.dll!CConnectionPoint::~CConnectionPoint() + 0x18 bytes
ieframe.dll!CShellOcx::~CShellOcx() + 0xf7 bytes
ieframe.dll!CWebBrowserOC::`scalar deleting destructor'() + 0x14 bytes
ieframe.dll!CAggregatedUnknown::CUnkInner::Release() + 0x474a1 bytes
ole32.dll!CStdIdentity::ReleaseCtrlUnk() Line 1149 C++
ole32.dll!CStdMarshal::Disconnect(unsigned long dwType) Line 3454 C++
ole32.dll!CStdMarshal::DisconnectAndRelease(unsigned long dwType) Line 3161 + 0x11 bytes C++
ole32.dll!COIDTable::ThreadCleanup() + 0x31bed bytes C++
ole32.dll!FinishShutdown() Line 1035 C++
ole32.dll!ApartmentUninitialize(int fHostThread) Line 1291 C++
ole32.dll!wCoUninitialize(COleTls & Tls, int fHostThread) Line 2709 + 0x7 bytes C++
ole32.dll!CoUninitialize() Line 2632 C++
imm32.dll!000007feff3832f2()
[Frames below may be incorrect and/or missing, no symbols loaded for imm32.dll]
msctf.dll!000007fefeea7d59()
ntdll.dll!RtlProcessFlsData() + 0x84 bytes
ntdll.dll!LdrShutdownThread() + 0x4b bytes
ntdll.dll!RtlExitUserThread() + 0x38 bytes
IEShims.dll!NS_CreateThread::DesktopIE_ThreadProc() + 0xd6 bytes
kernel32.dll!BaseThreadInitThunk() + 0xd bytes
ntdll.dll!RtlUserThreadStart() + 0x21 bytes
例外是访问冲突
你们有遇到过这样的情况吗?我可以应用什么策略来确定其根本原因? 到目前为止,我已经完成了以下操作
我使用了 windbg,但是我在 windbg 中遇到的异常与我在 VS2010 中得到的不同实际上异常是相同的“访问冲突”但堆栈跟踪不同。我不是很擅长 windbg 来解决这个问题。任何指针在windbg中追踪它? 我试图删除一些代码,但也没有成功。【问题讨论】:
在CoUninitialize
调用的那一刻,您应该已经终止了所有 COM 活动。你没有它发生。
堆损坏足以解释这一点。
【参考方案1】:
这很可能是由于错误的对象释放顺序而发生的。考虑以下示例:COM 对象 A 意味着拥有 COM 对象 B,因此预期的顺序是对象 A 被显式调用 Release()
并且在它的析构函数中它将调用对象 B 上的 Release()
。现在当 CoUnintialize()
被称为 COM 将强制释放 some 序列中的所有 COM 对象。因此,对象 B 有可能首先被称为 Release()
,现在对象 A 持有一个指向它认为是对象 B 的悬空指针,因此当对象 A Release()
被调用时,它会尝试利用悬空指针并运行到未定义的行为。
这个问题的解决方案是在调用CoUnintialize()
之前以正确的顺序显式释放对象。
【讨论】:
问题是在这种情况下 CoUnintialize 不是从我的代码中调用的。我在调用 CoUnintialize 时在我的代码中设置了断点并且它永远不会被调用。我只在那之前得到异常。 正如我们从堆栈跟踪中看到的那样,一些线程正在被破坏,那么您是否使用了工作线程?如果不是,那意味着你的主线程已经结束,如果它没有调用 CoUninitialize 就结束了,它可能因为一些严重的错误而被破坏(所以运行时调用 ExitProcess)。据我所知,可以在诸如 CoUninitialize 之类的 API 函数上设置断点。如果这样做,您可能会更好地了解哪个代码调用了 CoUninitialize。【参考方案2】:我有这个问题,红后
http://mfctips.com/2012/10/29/cfiledialogdomodal-causes-access-violation/
我怀疑问题在于将 QFileDialog 作为我的 Qmainwindow 方法的局部变量。然后我解决了它,将我的 Qfiledialog 作为 QMainwindow 的私有成员,如下所示:
//在MainWindow.h中
class MainWindow : public QMainWindow
Q_OBJECT
......
private:
......
QFileDialog *ptDialog;
.....
所以我在MainWindow构造函数中给ptDialog一个新的QfileDialog,并在MainWindow方法中根据我的需要调用ptDialog->exec(),如下:
//在MainWindow.cpp中
//构造函数
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
.....
ptDialog=new QFileDialog(this, tr("Abrir Imagem"),QCoreApplication::applicationDirPath(), "Imagens (*.png *.jpg *.jpeg *.bmp)");
......
//我想使用QFileDialog的任何方法
void MainWindow::LoadFile()
if(ptDialog->exec())
SetFile(ptDialog->selectedFiles().first());
我想,这样Qmainwindow只会在应用端释放,避免了这个问题。
【讨论】:
以上是关于如何在应用程序退出时诊断 comptr 版本中的异常的主要内容,如果未能解决你的问题,请参考以下文章
Spark 错误 - 退出状态:143。诊断:容器应请求终止