什么时候用零除零?调试器中的谜题(静态变量问题) [英] When is a divide by zero not a divide by zero? A puzzle in the debugger (static variable issues)

查看:167
本文介绍了什么时候用零除零?调试器中的谜题(静态变量问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很困惑,我认为我的调试器在说谎。我的代码中有以下循环:

I'm very confused and I think my debugger is lying to me. I have the following loop in my code:

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。

This loop has been executed hundreds of times during the course of my program and the two static variables are not changed anywhere in the code, they're written to just once when they're statically initialized and read from in the loop conditions and in one other place. Since they're user settings which are read from the Windows registry they almost always have the constant values of dwLockWaitTime = 60 and dwLockPollInterval = 5. So the loop is always doing 60 / 5.

很少,我得到一个崩溃转储,显示这行代码抛出一个除以零的错误。我检查了WinDbg说,并显示:

Very rarely, I get a crash dump which shows that this line of code has thrown a division by zero error. I've checked what WinDbg says and it shows:

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指令上发生了崩溃。 p>

I've checked the assembler code and it shows that the crash occurred on this div instruction.

00000001`3f72d744 8b0572151c00    mov     eax,dword ptr [dwLockWaitTime (00000001`3f8eecbc)]
00000001`3f72d74a f73570151c00    div     eax,dword ptr [dwLockPollInterval (00000001`3f8eecc0)]

因此,大家可以看到在值 000000013f8eecbc 被移入 eax ,然后 eax 000000013f8eecc0

So as you can see the value at 000000013f8eecbc was moved into eax and then eax was divided by the value at 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 正如我所料。那么,除以零在哪里?我的调试器躺着吗?当然,零除以被硬件抛出,所以它不能犯了一个错误?如果它在我的代码不同的地方有多大,调试器将显示在完全相同这个地方的指令指针是零一分?我承认,我很为难。

The constants 60 and 5 exactly as I'd expect. So where's the divide by zero??? Is my debugger lying? Surely the divide by zero has been thrown by the hardware so it can't have made a mistake about that? And if it was a divide by zero in a different place in my code what are the odds that the debugger would show the instruction pointer in exactly this place? I confess, I'm stumped..

推荐答案

由于代码是一个成员函数的一部分,而你调用此函数从多个线程,如果使用不符合C ++ 11标准的编译器, static 变量不是线程安全的。因此,在初始化这两个静态变量时,可能会得到数据库。

Since the code is part of a member function, and you're calling this function from multiple threads, the static variables are not thread-safe if using a compiler that does not conform to C++ 11 standards. Thus you may get data races when initializing those two static variables.

对于C ++ 11标准符合性编译器,现在保证静态变量由第一个线程初始化,而后续线程等待,直到静态初始化。

For a C++ 11 standard conforming compiler, static variables are now guaranteed to be initialized by the first thread, while subsequent threads wait until the static is initialized.

对于 Visual Studio 2010 及以下,静态局部变量不能保证是线程安全的,因为这些编译器符合到C ++ 03和C ++ 98标准。

For Visual Studio 2010 and below, static local variables are not guaranteed to be thread safe, since these compilers conform to the C++ 03 and C++ 98 standard.

对于 Visual Studio 2013 ,我不确定C ++ 11支持的水平在静态本地初始化。因此,对于Visual Studio 2013,您可能必须使用正确的同步来确保静态局部变量已正确初始化。

For Visual Studio 2013, I am not sure of the level of C++ 11 support in terms of static local initialization. Therefore, for Visual Studio 2013, you may have to use proper synchronization to ensure that static local variables are initialized correctly.

对于 Visual Studio 2015 ,以下链接显示预览版本已修复此项:

For Visual Studio 2015, the following link shows that the preview version has this item fixed:

http://www.visualstudio.com/en-us/news/vs2015-preview-vs.aspx

因此,您目前拥有的代码应该在VS 2015中正常工作。

So the code you currently have should work correctly for VS 2015.

Edit:对于 Visual Studio 2013 ,未实现静态本地线程安全初始化(Magic Statics),如此链接中所述:

For Visual Studio 2013, static local thread-safe initialization is not implemented ("Magic Statics"), as described in this link:

https://msdn.microsoft.com/en -us / library / hh567368.aspx

因此,我们可以谨慎地验证原始问题的原因是静态本地初始化问题和线程。所以解决方案(如果你想坚持VS 2013)是使用正确的同步,或重新设计你的应用程序,使静态变量不再需要。

Therefore, we can cautiously verify that the reason for the original problem is the static-local initialization issue and threading. So the solution (if you want to stick with VS 2013) is to use proper synchronization, or redesign your application so that static variables are no longer needed.

这篇关于什么时候用零除零?调试器中的谜题(静态变量问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆