代码之家  ›  专栏  ›  技术社区  ›  jfclavette

VisualStudio版本中令人困惑的STL错误

  •  1
  • jfclavette  · 技术社区  · 17 年前

    以下是相关代码:

    MyMapIterator myIt = m_myMap.find(otherID);
    
    if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_A)
    {
        //Prints stuff.  No side-effects whatsoever.
    }
    else if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second.foo == FOO_A)
    {
        //Prints stuff.  No side-effects whatsoever.
    }
    else if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second.foo == FOO_B && /*other meaningless conditions */)
    {
        //Prints stuff.  No side-effects whatsoever.
    }
    

    在调试中可以完美地工作,在发布时经常崩溃,禁用全局优化“修复了它”,现在什么都不起作用了。我得到一个:

    Microsoft Visual Studio C Runtime Library has detected a fatal error in [...]
    
    Press Break to debug the program or Continue to terminate the program. 
    

    第一个MyMapIterator::运算符->最后一个,如果

    映射是空的,我知道find应该返回end(),前两个效果比较是有效的。但不知怎的,第三次“我的!”m_myMap.end()'返回true,并且在&&被执行。

    编辑

    最后一个else如果不生成任何跳转!

        if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_A)
    009270BE  mov         ecx,dword ptr [this] 
    009270C4  add         ecx,0Ch 
    009270C7  lea         eax,[ebp-90h] 
    009270CD  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::end (8A21E0h) 
    009270D2  mov         esi,eax 
    009270D4  lea         edi,[myIt] 
    009270D7  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::const_iterator::operator!= (8A2220h) 
    009270DC  movzx       ecx,al 
    009270DF  test        ecx,ecx 
    009270E1  je          lux::Bar::DoStuff+0E4h (927154h) 
    009270E3  lea         esi,[myIt] 
    009270E6  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::iterator::operator-> (8A21F0h) 
    009270EB  cmp         dword ptr [eax+8],1 
    009270EF  jne         lux::Bar::DoStuff+0E4h (927154h) 
        {
             Stuff
        }
        else if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B)
    00927154  mov         ecx,dword ptr [this] 
    0092715A  add         ecx,0Ch 
    0092715D  lea         eax,[ebp-98h] 
    00927163  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::end (8A21E0h) 
    00927168  mov         esi,eax 
    0092716A  lea         edi,[myIt] 
    0092716D  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::const_iterator::operator!= (8A2220h) 
    00927172  movzx       edx,al 
    00927175  test        edx,edx 
    00927177  je          lux::Bar::DoStuff+17Ah (9271EAh) 
    00927179  lea         esi,[myIt] 
    0092717C  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::iterator::operator-> (8A21F0h) 
    00927181  cmp         dword ptr [eax+8],2 
    00927185  jne         lux::Bar::DoStuff+17Ah (9271EAh) 
        {
                //Stuff
         }
        else if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_C)
    009271EA  mov         ecx,dword ptr [this] 
    009271F0  add         ecx,0Ch 
    009271F3  lea         eax,[ebp-0A0h] 
    009271F9  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::end (8A21E0h) 
    009271FE  mov         esi,eax 
    00927200  lea         edi,[myIt] 
    00927203  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::const_iterator::operator!= (8A2220h) 
    00927208  lea         esi,[myIt] 
    0092720B  call        std::_Tree<std::_Tmap_traits<unsigned __int64,lux::Foo,std::less<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,lux::Foo> >,0> >::iterator::operator-> (8A21F0h) 
        {
                //Stuff in the condition and after
    
    9 回复  |  直到 17 年前
        1
  •  2
  •   morechilli    17 年前

    我怀疑其他地方的代码中有缓冲区溢出。

    另一个代码正在设法破坏发布代码正在使用的内存。

    改变其他随机代码也会改变行为,因为它会改变事物的相对位置。

    基本上,您需要查看大量代码或使用BoundsChecker之类的工具来查找错误。

    专注于数组或任何原始指针数学。也可以使用删除的指针。

    这样的bug如果写入到不会导致崩溃的地方,可能会隐藏很长时间。出于同样的原因,它们经常神秘地消失。

        2
  •  2
  •   jfclavette    17 年前

    伙计们。在经历了许多痛苦和泪水之后。为了至少暂时修复它,我不得不按照大多数人建议的格式对代码进行一些修改,这在第一种情况下应该是这样的:

    if (myIt != m_myMap.end())
    {
        if (myIt->second.userStatus == STATUS_A) 
        {
            //Prints stuff.  No side-effects whatsoever.
        }
        else if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)
        {        
            //Prints stuff.  No side-effects whatsoever.
        }
        else if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_B && /*other meaningless conditions */)
        {
            //Prints stuff.  No side-effects whatsoever.
        }
    }
    

    然而,这个bug仍然存在。这颗宝石修复了它:

    if (myIt != m_myMap.end())
    if (myIt != m_myMap.end())
    {
        if (myIt->second.userStatus == STATUS_A) 
        {
            //Prints stuff.  No side-effects whatsoever.
        }
        else if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)
        {        
            //Prints stuff.  No side-effects whatsoever.
        }
        else if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_B && /*other meaningless conditions */)
        {
            //Prints stuff.  No side-effects whatsoever.
        }
    }
    

        3
  •  1
  •   James Emerton    17 年前

    您可能在代码中有其他一些未显示的情况,导致映射中填充了一些无效数据。

    在调用之前尝试转储地图的内容 find()

        4
  •  1
  •   gbjbaanb    17 年前

    显然,任何东西都可能有bug,即使是VC编译器。因此,如果这段代码中有bug,可以用 #pragma 关闭优化。如果在那之后它仍然崩溃,那么代码中的其他东西正在破坏您的映射(然后您需要打开DrWatson以获取转储,这样您就可以在windbg中检查崩溃,并尝试找出它发生了什么)。

    #pragma optimize("g", off)
    

    #pragma optimize("", on)
    

        5
  •  1
  •   Adam Rosenfield    17 年前

    优化器确实会弄乱你的调试信息。这条线很有可能是 事实上 && 接线员,可能不是。

    要诊断真正的问题,您可能希望将最后一条if语句分解为如下内容:

    else if (myIt != m_myMap.end())
    {
        printf("TEST 1\n");
        if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_B && /*other meaningless conditions */)
        {
            //Prints stuff.  No side-effects whatsoever.
        }
    }
    
    printf("TEST 2\n");
    

    如果您得到“test1”的输出,那么您的迭代器有问题。如果您得到一个“test2”的输出,然后是一个崩溃,那么很明显,错误发生在后续代码中。如果既不打印“测试1”也不打印“测试2”,并且仍然在那里崩溃,那么就有问题了 真正地

        6
  •  1
  •   Aaron K    15 年前

    似乎只有在x64版本中才会发生(完全优化)。我的STL映射被确认为空(size()==0),但这行代码没有检测到空映射,而是进入for循环:

    typedef std::map<std::string,std::string> KeyValueMap;
    
    printf( "size: %d\n", ExtraHeaders.size() ); // prints "size: 0"
    
    for( KeyValueMap::iterator it= ExtraHeaders.begin(); it != ExtraHeaders.end(); it++ )
    {
        // this line is executed
        printf( "%s\t%s\n", (*it).first.c_str(), (*it).second.c_str() );
    }
    

        7
  •  0
  •   Michael Burr    17 年前

    是的,我知道我可以用迭代器等式检查来围绕整个过程,但这并不是最好的代码。关键是,它应该仍然有效,如果失败了,其他任何东西都可以。

    当然,按照这种逻辑,你别无选择。。。你做的任何事都是一种变通方法。

    myIt

    if (myIt != m_myMap.end())
    {
        if (myIt->second.userStatus == STATUS_A) 
        {
            //Prints stuff.  No side-effects whatsoever.
        }
        else if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)
        {        
            //Prints stuff.  No side-effects whatsoever.
        }
        else if (myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_B && /*other meaningless conditions */)
        {
            //Prints stuff.  No side-effects whatsoever.
        }
    }
    
        8
  •  0
  •   Dan Breslau    17 年前

    我认为你的假设可能是错误的:崩溃发生在 成功地 选中的 myIt != m_myMap.end() && myIt->second.userStatus 在同一个迭代中。我敢打赌,在第一次检查这些值之后,会立即发生崩溃。正是优化器让您看起来已经清除了前两个 if 条件

    cerr 紧接着崩溃之前。)

    // New code block
    MyMapIterator yourIt = m_myMap.find(otherID);
    if (yourIt != m_myMap.end() && yourIt->second.userStatus == STATUS_A || 
         yourIt->second.userStatus == STATUS_B)
    {
            cerr << "Hey, I can print something! " << std::ios::hex << this << endl;
    }
    
    // Original code
    MyMapIterator myIt = m_myMap.find(otherID);
    if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_A)
    {
            //Prints stuff.  No side-effects whatsoever.
    }
    else if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)
    {
            //Prints stuff.  No side-effects whatsoever.
    }
    else if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_B && /*other meaningless conditions */)
    {
            //Prints stuff.  No side-effects whatsoever.
    }
    
        9
  •  0
  •   jmucchiello    17 年前
    if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)
    

    为什么要使用访问userStatus。而foo与->?

    推荐文章