Dan*_*ger 7 c++ debugging exception-handling windbg visual-c++-2012
我无法在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);
Run Code Online (Sandbox Code Playgroud)
代码使用VC11 Update 1(CTP 3)编译.在运行优化的二进制文件时,它会getIndices()在几个循环之后挂起调用(更多关于此内容).我已经有了...
我并没有找到该代码访问分配的缓冲区,也没有任何堆损坏任何问题.但是,如果我禁用低碎片堆,问题就会消失.如果我为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
Run Code Online (Sandbox Code Playgroud)
为了完整起见,我将代码(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
Run Code Online (Sandbox Code Playgroud)
该线程挂起,等待属于操作系统异常处理代码的 SRW(精简读写锁)上的独占锁。该异常是由您的代码引起的。可以使用以下堆栈帧找到确切的异常及其详细信息。0034e848 77aa0133 0034e860 0034e8b0 0034e860 ntdll!RtlDispatchException+0x19 - RtlDispatchException的参数是指向EXCEPTION_RECORD 的指针。因此,如果您输入.exr 0034e860您可以看到异常记录。从异常记录中您可以知道对哪个地址的访问导致了异常(如果异常是访问冲突异常)。
因为,在执行这些步骤之后,您发现访问冲突是由于写入您在堆上正确分配的地址而发生的 - 您可以通过命令 !address " 找到包含该地址的虚拟页的保护属性虚拟地址”
正如您发现的那样,这些堆地址上的页面保护属性已更改为(通过某些代码)PAGE_READONLY,并且在看到其他线程的调用堆栈后,我有以下猜想,我认为这可能会帮助您找到根本原因。
我猜测 Windows 堆管理器在引发异常以指示堆损坏之前更改了页面属性。ole 堆中似乎也存在一些损坏 - 来自您显示的其他线程的调用堆栈。问题的根源可能是损坏堆的代码 - 堆随后发现该代码并引发异常,随后操作系统的异常机制实现代码启动并在能够调用之前挂在 SWR 锁上您或其他库代码中的异常处理程序。接下来,代码中的另一个无知线程正确地接触了堆内存,由于它已经发现了损坏,堆已经对其进行了保护,导致异常并使异常机制代码启动并陷入相同的状态僵局。鉴于您曾说过当程序在调试器下运行时问题无法重现,因此任何人都会猜测该问题存在一些计时问题或竞争条件。
| 归档时间: |
|
| 查看次数: |
2998 次 |
| 最近记录: |