¿Cuándo es una división por cero no una división por cero? Un rompecabezas en el depurador (problemas de variables estáticas)
Estoy muy confundido y creo que mi depurador me está mintiendo. Tengo el siguiente bucle en mi código:
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++)
{
...
Este bucle se ha ejecutado cientos de veces durante el curso de mi programa y las dos variables estáticas no se cambian en ninguna parte del código, se escriben solo una vez cuando se inicializan estáticamente y se leen en las condiciones del bucle y en una otro lugar. Como son configuraciones de usuario que se leen desde el registro de Windows, casi siempre tienen los valores constantes de dwLockWaitTime = 60 y dwLockPollInterval = 5. Por lo tanto, el ciclo siempre está haciendo 60/5.
Muy raramente, recibo un volcado por caída que muestra que esta línea de código ha arrojado una división por error cero. He comprobado lo que dice WinDbg y muestra:
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.
Revisé el código del ensamblador y muestra que se produjo el bloqueo en esta instrucción div.
00000001`3f72d744 8b0572151c00 mov eax,dword ptr [dwLockWaitTime (00000001`3f8eecbc)]
00000001`3f72d74a f73570151c00 div eax,dword ptr [dwLockPollInterval (00000001`3f8eecc0)]
Entonces como puedes ver el valor en000000013f8eecbc
fue trasladado aeax
y entonceseax
fue dividido por el valor en000000013f8eecc0
.
¿Qué hay en esos dos valores que preguntas?
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
Las constantes60
y5
exactamente como esperaba. Entonces, ¿dónde está la división por cero? ¿Mi depurador está mintiendo? ¿Seguramente la división por cero ha sido lanzada por el hardware, por lo que no puede haber cometido un error? Y si fue una división por cero en un lugar diferente en mi código, ¿cuáles son las probabilidades de que el depurador muestre el puntero de instrucciones exactamente en este lugar? Lo confieso, estoy perplejo ...