【发布时间】:2015-01-22 19:20:23
【问题描述】:
我很困惑,我认为我的调试器在骗我。我的代码中有以下循环:
MyClass::UploadFile(CString strFile)
{
...
static DWORD dwLockWaitTime = EngKey::GetDWORD(DNENG_SERVER_UPLOAD_LOCK_WAIT_TIME, DNENG_SERVER_UPLOAD_LOCK_WAIT_TIME_DEFAULT);
static DWORD dwLockPollInterval = EngKey::GetDWORD(DNENG_SERVER_UPLOAD_LOCK_POLL_INTERVAL, DNENG_SERVER_UPLOAD_LOCK_POLL_INTERVAL_DEFAULT);
LONGLONG llReturnedOffset(0LL);
BOOL bLocked(FALSE);
for (DWORD sanity = 0; (sanity == 0 || status == RESUMABLE_FILE_LOCKED) && sanity < (dwLockWaitTime / dwLockPollInterval); sanity++)
{
...
在我的程序过程中,这个循环已经执行了数百次,并且两个静态变量在代码中的任何地方都没有改变,当它们被静态初始化并在循环条件中读取时,它们只被写入一次在另一个地方。由于它们是从 Windows 注册表中读取的用户设置,因此它们几乎总是具有 dwLockWaitTime = 60 和 dwLockPollInterval = 5 的常量值。所以循环总是执行 60 / 5。
很少,我得到一个崩溃转储,它表明这行代码已经引发了除以零错误。我检查了 WinDbg 的内容并显示:
FAULTING_IP:
procname!CServerAgent::ResumableUpload+54a [serveragent.cpp @ 725]
00000001`3f72d74a f73570151c00 div eax,dword ptr [proc!dwLockPollInterval (00000001`3f8eecc0)]
EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 000000013f72d74a (proc!CServerAgent::ResumableUpload+0x000000000000054a)
ExceptionCode: c0000094 (Integer divide-by-zero)
ExceptionFlags: 00000000
NumberParameters: 0
ERROR_CODE: (NTSTATUS) 0xc0000094 - {EXCEPTION} Integer division by zero.
我检查了汇编代码,它显示崩溃发生在这个 div 指令上。
00000001`3f72d744 8b0572151c00 mov eax,dword ptr [dwLockWaitTime (00000001`3f8eecbc)]
00000001`3f72d74a f73570151c00 div eax,dword ptr [dwLockPollInterval (00000001`3f8eecc0)]
如您所见,000000013f8eecbc 的值被移动到eax,然后eax 除以000000013f8eecc0 的值。
你问的这两个值是什么?
0:048> dd 00000001`3f8eecbc
00000001`3f8eecbc 0000003c 00000005 00000001 00000000
00000001`3f8eeccc 00000000 00000002 00000000 00000000
00000001`3f8eecdc 00000000 7fffffff a9ad25cf 7fffffff
00000001`3f8eecec a9ad25cf 00000000 00000000 00000000
00000001`3f8eecfc 00000000 00000000 00000000 00000000
00000001`3f8eed0c 00000000 00000000 00000000 00000000
00000001`3f8eed1c 00000000 00000000 00000000 00000000
00000001`3f8eed2c 00000000 00000000 00000000 00000000
0:048> dd 000000013f8eecc0
00000001`3f8eecc0 00000005 00000001 00000000 00000000
00000001`3f8eecd0 00000002 00000000 00000000 00000000
00000001`3f8eece0 7fffffff a9ad25cf 7fffffff a9ad25cf
00000001`3f8eecf0 00000000 00000000 00000000 00000000
00000001`3f8eed00 00000000 00000000 00000000 00000000
00000001`3f8eed10 00000000 00000000 00000000 00000000
00000001`3f8eed20 00000000 00000000 00000000 00000000
00000001`3f8eed30 00000000 00000000 00000000 00000000
常量60 和5 完全符合我的预期。那么除以零在哪里???我的调试器在撒谎吗?肯定是硬件已经抛出了除以零,所以它不会犯错吗?如果它在我的代码中的不同位置被零除,那么调试器会在这个位置显示指令指针的几率是多少?我承认,我被难住了..
【问题讨论】:
-
您在 minidump 中看到预期值的事实并不能证明它在指令执行时具有预期值。例如,线程竞赛的非常经典的行为,小型转储不是在引发异常的确切时间记录的瞬时快照。软 RAM 错误是此类无法解释的事故的另一个来源。因此,如果您确定线程不是一个因素,那么给客户的最佳建议是更换他的 RAM 模块。
-
关于这一思路的两点。如果转储中的内容(顺便说一下完整转储而不是迷你转储)不正确,则它必须相对于执行的内容已经过时,而不是相反。这意味着如果这两个值被破坏了,那么之后就不得不将它们恢复为预期值......
-
@Benj -
So the loop is always doing 60 / 5.这可能无法回答您的问题,但为什么不预先计算此值并将其存储在变量中,然后在循环中使用该变量? -
@Benj - 另外,如果您还没有这样做,我认为是时候考虑记录这些(重要的)值(dwLockWaitTime、dwLockPollInterval),而不是试图找出它们的来源一个小型转储。
-
@Benj - 你用的是什么编译器?根据您的描述,我认为您遇到了问题。