调试Win32应用程序挂起
Debug Win32 application hang
我很难在Win32应用程序中找到挂起的原因。该软件在紧密的循环中将一些数据呈现为OpenGL视觉效果:
std::vector<uint8_t> indices;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_DOUBLE, 0, vertexDataBuffer);
while (...) {
// get index type (1, 2, 4) and index count
indices.resize(indexType * count);
// get indices into "indices" buffer
getIndices(indices.data(), indices.size()); //< seems to hang here!
// draw (I'm using the correct parameters)
glDrawElements(GL_TRIANGLES_*, count, GL_UNSIGNED_*);
}
glDisableClientState(GL_VERTEX_ARRAY);
使用VC11更新1(CTP 3)编译代码。运行优化的二进制文件时,它将悬挂在getIndices()
的呼叫中(以下有关此循环的更多信息)。我已经有...
- 三重验证了所有缓冲区,甚至附加了CRC,以确保我没有任何缓冲区超支
- 在循环内添加了呼叫heapvalidate(),以确保堆不会损坏
- 二手应用程序
- 使用GFLAGS和PAGEHEAP启用了堆分配监视。
- 当应用程序锁定时闯入windbg
我做过不是找到访问分配的缓冲区的代码的任何问题,也没有任何堆损坏。但是,如果我禁用低碎片堆,问题就会消失。如果我为indices
缓冲区使用单独的(低碎片)堆,它也会消失。
无论如何,这是导致死锁的堆栈跟踪:
0:000> kb
ChildEBP RetAddr Args to Child
0034e328 77b039c3 00000000 0034e350 00000000 ntdll!ZwWaitForKeyedEvent+0x15
0034e394 77b062bc 77b94724 080d36a8 0034e464 ntdll!RtlAcquireSRWLockExclusive+0x12e
0034e3c0 77aeb652 0034e464 0034e4b4 00000000 ntdll!RtlpCallVectoredHandlers+0x58
0034e3d4 77aeb314 0034e464 0034e4b4 77b94724 ntdll!RtlCallVectoredExceptionHandlers+0x12
0034e44c 77aa0133 0034e464 0034e4b4 0034e464 ntdll!RtlDispatchException+0x19
0034e44c 77b062c5 0034e464 0034e4b4 0034e464 ntdll!KiUserExceptionDispatcher+0xf
0034e7bc 77aeb652 0034e860 0034e8b0 00000000 ntdll!RtlpCallVectoredHandlers+0x61
0034e7d0 77aeb314 0034e860 0034e8b0 0034ec28 ntdll!RtlCallVectoredExceptionHandlers+0x12
0034e848 77aa0133 0034e860 0034e8b0 0034e860 ntdll!RtlDispatchException+0x19
0034e848 1c43c666 0034e860 0034e8b0 0034e860 ntdll!KiUserExceptionDispatcher+0xf
0034ebe8 1c43c4e5 0034ec28 080d35d0 080d35d6 lcdb4!lc::db::PackedIndices::unpackIndices<unsigned char>+0x86
0034ec14 1c45922d 0034ec28 080d35d0 00000006 lcdb4!lc::db::PackedIndices::unpack+0xb5
...
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx getIndices
有关完整性,我发布了lc::db::PackedIndices::unpackIndices()
的代码,包括添加的所有调试代码,http://ideone.com/svvxx7。
触发呼叫KiUserExceptionDispatcher
的代码为(*p++) = static_cast<T>(index);
(mov dword ptr [esp+10h],eax
)。
我似乎无法弄清楚发生了什么。似乎已经抛出了一个例外,但是我的异常处理程序都没有被称为。应用程序只是悬挂。我检查了任何僵持的关键部分(!lock
),但没有发现。此外,我不明白为什么要提出异常,因为内存位置都是有效的。谁能给我一些提示?
更新
我试图找到被抛出的异常类型:
0:000> s -d esp L1000 1003f
0028ebdc 0001003f 00000000 00000000 00000000 ?...............
0028efd8 0001003f 00000000 00000000 00000000 ?...............
0:000> .cxr 0028ebdc
eax=77b94724 ebx=0804be30 ecx=00000002 edx=00000004 esi=77b94724 edi=0804be28
eip=77b062c5 esp=0028eec4 ebp=0028eee4 iopl=0 nv up ei ng nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010287
ntdll!RtlpCallVectoredHandlers+0x61:
77b062c5 ff03 inc dword ptr [ebx] ds:002b:0804be30=00000001
0:000> .cxr 0028efd8
eax=0000003b ebx=00000001 ecx=0804bd98 edx=0028f340 esi=0028f340 edi=04b77580
eip=1c43c296 esp=0028f2c0 ebp=0028f2fc iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
lcdb4!lc::db::PackedIndices::unpackIndices<unsigned char>+0x36:
1c43c296 8801 mov byte ptr [ecx],al ds:002b:0804bd98=3e
线程正在等待属于srw(纤细的读写锁)的独家锁,该锁属于OS异常处理代码。该例外是由您的代码引起的。可以使用以下堆栈框架找到确切的例外及其细节。 0034E848 77AA0133 0034E860 0034E8B0 0034E860 ntdll!rtldispatchExecception 0x19 - 与 rtldispatchExection rtldispatchExection sT_S_S pro 因此,如果您键入 .EXR 0034E860 您可以看到异常记录。从例外记录,您将知道访问哪个地址导致例外(如果例外是访问违规例外)。
。由于在这些步骤之后,您发现访问违规发生是由于写入您在堆上正确分配的地址而发生的 - 您可以找到包含该地址的虚拟页面的保护属性!地址"虚拟地址"
当您发现页面保护属性已更改为(通过某些代码) page_readonly 在那些堆地址上,看到其他线程的呼叫堆栈后,我有以下猜想认为可以帮助您找到根本原因。
我猜想Windows Heap Manager在提出例外之前更改页面属性以表明堆损坏。从您展示的其他线程的呼叫堆栈中,似乎也有一些损坏。问题的根源可能是损坏堆的代码 - 堆随后找到并提出了例外,此后,OS启动的例外机制实现代码,并在能够打电话之前被挂在SWR锁上您或其他库代码中的异常处理程序。在您的代码中遵循另一个无知的线程,正确触摸了堆内存,由于其已经发现的损坏,堆已经受到保护,导致例外并使异常机制代码启动并掉入同一机构僵局。鉴于您曾说过该程序在调试器下运行时无法再现问题,因此任何人都猜想问题存在某个时机问题或种族条件。
堆栈跟踪讲述了这个故事。您的程序正在崩溃,这是违反访问的例外,这是C 代码的典型故障模式,通常由堆损坏触发。然后,Windows试图调用异常过滤器,以查找任何愿意处理异常的代码。首先是AddVectoredExceptionHandler()安装的处理程序。当其中一个处理程序又导致崩溃时,必须锁定要防止重新进入。
这就是雄鹿停止的地方。确切为什么从堆栈跟踪中不清楚。可能是因为另一个线程也陷入了堆腐败,并且忙于处理例外并锁定了锁。使用调试 Windows 线程查看它们。但更有可能的是,过程状态被堵塞了,以至于锁对象本身也损坏了。不太可能,但确实发生了。
是的,关闭低碎片堆堆有一个隐藏堆腐败的诀窍。内存布局将非常不同,因此无论导致损坏的代码现在都可能已经击败了一些无辜的东西。当然不是解决方案。
调试 异常,请勾选" Win32异常"的抛出的复选框。现在,在抛出异常时,调试器将停止。至少您会知道正在抛出什么例外。最终,您确实需要找出堆腐败发生的位置。它从来没有位于崩溃的代码中,祝您好运。您不得泄漏任何状态的已知问题,否则记忆损坏后来发生。
尝试禁用您可以的所有状态(gldisableclientstate),使用Apitrace找出您忘记了哪一个。
测试图形驱动程序中内存损坏的一种简单方法是在另一个板/驱动程序上测试,或者强制软件渲染。
- 有时ShowWindow从不调用OnShowWindow,主应用程序挂起
- C++多线程应用程序将永远挂起
- 如何在Cocos2d Android应用程序中获得呼叫/挂起事件
- 当后端响应需要很长时间时,WXWIDGET应用程序会挂起
- Eclipse PTP挂起OpenMPI应用程序的启动调试会话
- 安卓 |如何调试应用启动或挂起应用,直到调试器连接
- 调试Win32应用程序挂起
- 为什么我的多线程应用程序挂起
- 在自定义组合框下拉列表控件上等待超过5秒会导致win32 C++应用程序在Windows7中挂起
- linux上的c++应用程序,在终止之前挂起
- X由于应用程序(使用C++、Qt、OpenGL)而挂起
- 使用应用程序验证程序调试时应用程序挂起
- QGraphicsScene - 添加带有少量不透明点的大透明像素图时,应用程序会挂起很长时间
- 应用程序在 的协同创建实例期间挂起.基于 NET 的 COM 对象
- 分析应用程序的挂起转储
- 在IEnumWbemClassObject调用next会挂起应用程序
- MFC应用程序挂起在发出终止信号的线程中
- 在QImage上渲染QWebElement时,QT应用程序挂起
- 查找位置(寻找c++初学者)以创建Windows Vista x64 Ultimate的挂起进程程序
- visualstudio2015在调试期间挂起默认控制台应用程序文件