1

VisualStudio2005のオプティマイザーのバグであると確信しています。問題はSTLマップにあります。

関連するコードは次のとおりです。

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::operator->で発生します。

マップは空です。findがend()を返す必要があることはわかっています。その効果に対する最初の2つの比較は機能します。しかし、どういうわけか、3回目の'myIt!= m_myMap.end()'はtrueを返し、&&の右側が実行されます。

'myIt!= m_myMap.end()'のバリアントが同じファイルでtrueを返すため、他のさまざまな場所がこのように失敗しますが、これは私にとって、他のほとんどの可能性を排除する場所です。以前は、マップを踏みにじっていたのはバッファオーバーフローだと思っていましたが、コードを振り返ってみてください。他のスレッドがそれを踏みつけていないことを私は確信しています、そしてこれは100%再現可能です。

それで、私はここから何をしますか。これは、パフォーマンスに少しでも影響されません。正常に機能するために必要です。任意のオプションが受け入れられます。はい、イテレータの等価性チェックですべてを囲むことができることはわかっていますが、これは最も優れたコードではありません。重要なのは、それはまだ機能するはずであり、それが失敗した場合、他の何でもできるということです。

編集

最後の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
4

9 に答える 9

2

さてみんな。多くの痛みと涙の後。少なくとも一時的に修正するには、ほとんどの人が提案する形式にコードを少し作り直す必要がありました。これは、最初のケースではそうあるべきでした。

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.
    }
}

ただし、バグはまだ存在していました。この宝石はそれを修正しました:

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.
    }
}

はい。ifを2倍にすると、テスト後にジャンプ命令が発行されました。

于 2009-05-07T23:15:50.470 に答える
2

バッファオーバーランが含まれているコードが他の場所にあると思われます。

この他のコードは、投稿されたコードが使用しているメモリを破壊することに成功しています。

デバッグモードでは、追加のメモリパディングによって動作が変わります。

他のランダムコードを変更すると、物事の相対的な位置がシフトするため、動作も変更されます。

基本的に、エラーを見つけるには、多くのコードを確認するか、BoundsCheckerなどのツールを使用する必要があります。

配列または生のポインタ計算に集中します。また、削除されたポインタの使用。

このようなバグは、クラッシュを引き起こさない場所に書き込むと、長い間隠れることがあります。同じ理由で、彼らはしばしば不思議なことに姿を消します。

于 2009-05-07T17:09:50.197 に答える
1

表示していないコードに他の条件があり、マップに無効なデータが入力されている可能性があります。

を呼び出す前にマップの内容をダンプしてみてfind()、コードの残りの部分で初期化されていない可能性のある値を探してください。

于 2009-05-07T16:58:31.847 に答える
1

明らかに、VCコンパイラでさえ、何でもバグがある可能性があります。したがって、コードのこのセクションにバグがある場合は、それを#pragmaでラップして、最適化をオフにすることができます。それでもクラッシュする場合は、コード内の他の何かがマップをゴミ箱に入れています(そして、ダンプを取得するためにDrWatsonをオンにして、windbgのクラッシュを調べて、何が起こっているのかを調べる必要があります)。

最適化をオフにするには、次を使用します。

#pragma optimize("g", off)

オンに戻すには、オフからオンに変更するか、特殊なケースを使用します

#pragma optimize("", on)

これにより、最適化設定がプロジェクトのデフォルトにリセットされます。

于 2009-05-07T16:59:53.557 に答える
1

オプティマイザは実際にデバッグ情報を台無しにします。近くの別の回線で実際に障害が発生している回線が発生する可能性は非常に高くなります。デバッガーがオペレーターの後半で例外が発生していることを通知している場合でも、&&おそらくそうではありません。

実際の問題を診断するには、最後の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」の出力が表示されてからクラッシュした場合は、明らかに後続のコードでエラーが発生しています。「TEST1」も「TEST2」も印刷されず、それでもクラッシュする場合は、何かが本当に間違っています。

于 2009-05-07T17:06:41.217 に答える
1

私はこれとまったく同じ問題に遭遇したと思います。

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() );
}

私にはコンパイラのバグのように感じます。

于 2011-01-26T22:36:45.807 に答える
0

はい、イテレータの等価性チェックですべてを囲むことができることはわかっていますが、これは最も優れたコードではありません。重要なのは、それはまだ機能するはずであり、それが失敗した場合、他の何でもできるということです。

もちろん、そのロジックではオプションはありません...あなたがすることはすべて回避策です。

私の最初のアプローチは、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.
    }
}
于 2009-05-07T17:09:30.540 に答える
0

おそらく間違っていると思います。同じ反復で正常にチェックした後にクラッシュが発生するということです。myIt != m_myMap.end() && myIt->second.userStatusこれらの値が最初に調べられた直後にクラッシュが発生することは間違いありません。if最初の2つの条件をクリアしたように見せかけるのはオプティマイザーです。

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.
}
于 2009-05-07T17:27:30.933 に答える
0
if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)

を使用してuserStatusにアクセスするのはなぜですか。とfooと->?

于 2009-05-07T17:35:32.443 に答える