문제

제가 확신하는 것은 Visual Studio 2005의 최적화 프로그램에 있는 버그입니다.문제는 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-> 마지막 else if

맵은 비어 있습니다. find가 end()를 반환했어야 한다는 것을 알고 있습니다. 해당 효과에 대한 처음 두 비교가 작동합니다.그런데 어찌됐든 세 번째 'myIt != m_myMap.end()'가 true를 반환하고 &&의 오른쪽이 실행됩니다.

같은 파일에서 true를 반환하는 'myIt != m_myMap.end()' 변형을 사용하면 여러 다른 곳에서 이와 같이 실패하지만, 나에게는 이것이 대부분의 다른 가능성을 배제하는 것입니다.예전에는 내 지도를 쿵쿵쿵 밟는 것이 버퍼 오버플로라고 생각했는데, 코드를 다시 살펴보세요.나는 다른 어떤 스레드도 그것을 밟고 있지 않으며 이것은 100% 재현 가능하다는 것을 확신합니다.

그럼 여기서 무엇을 해야 할까요?이는 성능에 전혀 민감하지 않습니다.나는 그것이 제대로 작동하기 위해 필요합니다.어떤 옵션이라도 허용됩니다.예, 반복자 동등성 검사로 모든 ​​것을 둘러쌀 수 있지만 이것이 가장 좋은 코드는 아니라는 것을 알고 있습니다.요점은 여전히 ​​작동해야 한다는 것입니다. 작동하지 않으면 다른 어떤 것도 작동할 수 있습니다.

편집하다

마지막 else-if는 점프를 생성하지 않습니다!

    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
도움이 되었습니까?

해결책 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를 두 배로 늘리면 테스트 후에 점프 명령이 방출됩니다.

다른 팁

버퍼 오버런이 있는 코드가 다른 곳에 있는 것 같습니다.

이 다른 코드는 게시된 코드가 사용하는 메모리를 파괴하고 있습니다.

디버그 모드에서는 추가 메모리 패딩으로 인해 동작이 변경됩니다.

다른 무작위 코드를 변경하면 사물의 상대적 위치가 이동하므로 동작도 변경됩니다.

기본적으로 오류를 찾으려면 많은 코드를 검토하거나 BoundsChecker와 같은 도구를 사용해야 합니다.

배열이나 원시 포인터 수학에 집중하세요.또한 삭제된 포인터를 사용하는 경우도 있습니다.

이와 같은 버그는 충돌을 일으키지 않는 곳에 쓰면 오랫동안 숨겨질 수 있습니다.같은 이유로 그들은 종종 신비롭게 사라지곤 합니다.

코드에 표시되지 않은 다른 조건이 있어 지도가 잘못된 데이터로 채워지는 것 같습니다.

전화를 걸기 전에 지도의 내용을 버려보세요. find(), 나머지 코드에서 초기화되지 않은 값이 있는지 찾아보세요.

분명히 모든 것, 심지어 VC 컴파일러에도 버그가 있을 수 있습니다.따라서 이 코드 섹션에 버그가 있는 경우 이를 다음과 같이 래핑할 수 있습니다. #프라그마 최적화를 끄려면그 후에도 여전히 충돌이 발생하면 코드의 다른 부분이 지도를 폐기하는 것입니다. 그런 다음 DrWatson을 켜서 덤프를 가져와서 windbg에서 충돌을 검사하여 무슨 일이 일어났는지 알아내야 합니다.

최적화를 끄려면 다음을 사용하십시오.

#pragma optimize("g", off)

다시 켜려면 끄기를 켜기로 변경하거나 특수 케이스를 사용하세요.

#pragma optimize("", on)

그러면 최적화 설정이 프로젝트 기본값으로 재설정됩니다.

최적화 프로그램은 실제로 디버깅 정보를 엉망으로 만듭니다.다음과 같은 라인이 나타날 가능성이 매우 높습니다. 실제로 근처의 다른 회선에서 오류가 발생했습니다.디버거가 작업 후반부에서 예외가 발생하고 있다고 알려주더라도 && 운영자님, 아마 그렇지 않을 것 같습니다.

실제 문제를 진단하려면 마지막 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");

"TEST 1"이라는 출력이 나오면 반복자에 문제가 있는 것입니다."TEST 2"라는 출력이 나온 후 충돌이 발생하면 분명히 후속 코드에서 오류가 발생하고 있는 것입니다."TEST 1"이나 "TEST 2"가 모두 인쇄되지 않고 여전히 충돌이 발생하는 경우 문제가 있는 것입니다. 정말 잘못된.

나는 이와 똑같은 문제에 직면했다고 생각합니다.

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

나에게는 컴파일러 버그처럼 느껴집니다.

예, 반복자 동등성 검사로 모든 ​​것을 둘러쌀 수 있지만 이것이 가장 좋은 코드는 아니라는 것을 알고 있습니다.요점은 여전히 ​​작동해야 한다는 것입니다. 작동하지 않으면 다른 어떤 것도 작동할 수 있습니다.

물론, 그 논리로는 선택의 여지가 없습니다...당신이하는 모든 일은 해결 방법입니다.

내 첫 번째 접근 방식은 다음을 확인하는 블록에 항목을 래핑하는 것입니다. 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.
    }
}

내 생각에 당신은 아마도 거짓일 수도 있는 가정을 하고 있는 것 같습니다.충돌이 발생한 후에 발생한다는 것 성공적으로 확인됨 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.
}
if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)

왜 userStatus에 .그리고 foo는 -> ?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top