Непонятная ошибка STL в выпуске в Visual Studio - PullRequest
1 голос
/ 07 мая 2009

Я уверен, что есть ошибка в оптимизаторе в 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-> последнего, если

Карта пуста, я знаю, что find должен был вернуть end (), первые два сравнения с этим эффектом работают. Но каким-то образом третий раз myIt! = M_myMap.end () возвращает значение true, и выполняется правая часть &&.

В некоторых других местах происходит сбой, как в случае с вариантом 'myIt! = M_myMap.end ()', возвращающим true в том же файле, но для меня это тот, который исключает большинство других возможностей. Раньше я думал, что это переполнение буфера, которое топает мою карту, но оглянемся на код. Я уверен, что никакой другой поток не топает это, и это на 100% воспроизводимо.

Итак, что мне делать отсюда. Это не чувствительно к производительности в малейшей степени. Мне просто нужно, чтобы он работал как надо. Любой вариант приемлем. Да, я знаю, что мог бы окружить все это проверкой равенства итераторов, и это не самый хороший код. Дело в том, что он все еще должен работать, и если это не сработает, все остальное может.

EDIT

Последний оператор if-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

Ответы [ 9 ]

2 голосов
/ 08 мая 2009

Ну, ребята. После большой боли и слез. Чтобы исправить это хотя бы временно, мне пришлось немного переделать код в форму, предложенную большинством людей, как это должно было быть в первом случае:

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 голосов
/ 07 мая 2009

Я подозреваю, что у вас есть код в другом месте, в котором переполнен буфер.

Этот другой код управляет разрушением памяти, которую использует опубликованный код.

В режиме отладки дополнительное заполнение памяти изменит поведение.

Изменение другого случайного кода также изменит поведение, поскольку это изменит относительное положение вещей.

В основном вам нужно просмотреть много кода или использовать такой инструмент, как BoundsChecker, чтобы найти ошибку.

Сконцентрируйтесь на массивах или любых сырых математических указателях. Также любое использование удаленных указателей.

Ошибки, подобные этой, могут долго скрываться, если они пишут в место, которое не вызывает сбой. По той же причине они часто таинственно исчезают.

1 голос
/ 27 января 2011

Я думаю, что столкнулся с точно такой же проблемой.

Кажется, только в версии 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() );
}

Мне кажется, что это ошибка компилятора.

1 голос
/ 07 мая 2009

Оптимизатор действительно портит вашу информацию отладки. Есть очень хороший шанс, что линия, которая на самом деле не работает на другой соседней линии. Даже если отладчик сообщает вам, что исключение происходит во второй половине оператора &&, вероятно, это не так.

Чтобы диагностировать реальную проблему, вы можете пожелать разбить последний оператор 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» и затем происходит сбой, то очевидно, что ошибка возникает в последующем коде. Если ни «ТЕСТ 1», ни «ТЕСТ 2» не печатает, и там все равно происходит сбой, значит что-то действительно неправильно.

1 голос
/ 07 мая 2009

, очевидно, что-нибудь может иметь ошибку, даже компилятор VC. поэтому, если в этом разделе кода есть ошибка, вы можете обернуть ее в # pragma , чтобы отключить оптимизацию. Если после этого все еще происходит сбой, то что-то еще в вашем коде уничтожает вашу карту (и затем вам нужно включить DrWatson, чтобы получить дампы, чтобы вы могли проверить сбой в windbg, чтобы попытаться выяснить, что с ним произошло).

Чтобы отключить оптимизацию, используйте:

#pragma optimize("g", off)

чтобы включить его, либо выключите, либо используйте специальный чехол

#pragma optimize("", on)

, который сбрасывает ваши настройки оптимизации на значения по умолчанию для проекта.

1 голос
/ 07 мая 2009

Кажется вероятным, что в коде вы не указали какое-то другое условие, которое приводит к заполнению карты недействительными данными.

Попробуйте выгрузить содержимое карты перед вашим вызовом find() и найдите все возможные неинициализированные значения в остальной части кода.

0 голосов
/ 07 мая 2009
if (myIt != m_myMap.end() && myIt->second.userStatus == STATUS_B && myIt->second->foo == FOO_A)

Почему вы обращаетесь к userStatus с помощью. и foo с ->?

0 голосов
/ 07 мая 2009

Я думаю, вы делаете предположение, которое, вероятно, неверно: сбой происходит после того, как успешно проверил myIt != m_myMap.end() && myIt->second.userStatus в той же итерации. Могу поспорить, что сбой следует сразу же после первого анализа этих значений. Это оптимизатор, который делает вид, что вы очистили первые два if условия.

Попробуйте вставить в цикл совершенно другой блок кода и посмотрите, не сработает ли он там (я уверен, что это произойдет - я не думаю, что вы увидите вывод cerr, непосредственно предшествующий сбою.) 1008 *

// 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.
}
0 голосов
/ 07 мая 2009

Да, я знаю, что мог бы окружить все это проверкой равенства итераторов, и это не самый хороший код. Дело в том, что он все еще должен работать, и если это не сработает, все остальное может.

Конечно, с такой логикой у вас нет вариантов ... Все, что вы делаете, это обходной путь.

Я думаю, что мой первый подход заключается в том, чтобы обернуть материал в блок, который проверяет, что 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.
    }
}
...