Pregunta

Tengo lo que estoy bastante seguro es un error en el optimizador en Visual Studio 2005. El problema es con un mapa STL.

Aquí está el código relevante:

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

Funciona perfectamente en la depuración, solía bloquearse en el lanzamiento y deshabilita las optimizaciones globales "lo arregló" Ahora nada funciona. Me sale un:

Microsoft Visual Studio C Runtime Library has detected a fatal error in [...]

Press Break to debug the program or Continue to terminate the program. 

Esto sucede en el primer MyMapIterator :: operator- > del último si

El mapa está vacío, sé que find debería haber devuelto end (). Las dos primeras comparaciones con ese efecto funcionan. Pero de alguna manera, la tercera vez 'myIt! = M_myMap.end ()' devuelve verdadero, y el lado derecho de & amp; & amp; se ejecuta.

Varios otros lugares fallan como este con una variante de 'myIt! = m_myMap.end ()' que devuelve verdadero en el mismo archivo, pero este es, para mí, el que descarta la mayoría de las otras posibilidades. Solía ??pensar que era un desbordamiento de búfer que estaba pisando fuerte en mi mapa, pero eche un vistazo al código. Estoy seguro de que ningún otro hilo está pisando fuerte, y esto es 100% reproducible.

Entonces, ¿qué hago desde aquí? Esto no es sensible al rendimiento en lo más mínimo. Solo necesito que funcione como debería. Cualquier opción es aceptable. Sí, sé que podría rodear todo con la verificación de igualdad del iterador y no es el código más agradable. El punto es que aún debería funcionar, y si eso falla, cualquier otra cosa puede hacerlo.

EDIT

¡El último si no genera ningún salto!

    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
¿Fue útil?

Solución 2

Bueno chicos. Después de mucho dolor y lágrimas. Para solucionarlo, al menos temporalmente, tuve que modificar el código un poco al formulario sugerido por la mayoría de las personas, que es como debería haber sido en el primer caso:

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

Sin embargo, el error todavía estaba presente. Esta gema lo arregló:

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

Sí Doblar el if resultó en una instrucción de salto emitida después de la prueba.

Otros consejos

Sospecho que tiene código en otro lugar que tiene un buffer sobre ejecutado en él.

Este otro código está logrando destruir la memoria que está usando el código publicado.

En modo de depuración, el relleno de memoria adicional cambiará el comportamiento.

Cambiar otro código aleatorio también cambiará el comportamiento, ya que cambiará la posición relativa de las cosas.

Básicamente, deberá revisar una gran cantidad de código o utilizar una herramienta como BoundsChecker para encontrar el error.

Concéntrese en matrices o cualquier matemática de puntero sin formato. También cualquier uso de punteros eliminados.

Los errores como este pueden ocultarse durante mucho tiempo si escriben en un lugar que no provoque un bloqueo. Por la misma razón, a menudo desaparecen misteriosamente.

Parece probable que tenga alguna otra condición en el código que no haya mostrado que esté causando que el mapa se complete con algunos datos no válidos.

Intente deshacerse del contenido del mapa antes de su llamada a find () , y busque posibles valores no inicializados en el resto del código.

obviamente cualquier cosa puede tener errores, incluso el compilador de VC. así que si hay un error en esta sección del código, puede envolverlo en un # pragma para desactivar las optimizaciones. SI todavía se bloquea después de eso, entonces algo más en su código está tirando a la basura su mapa (y luego necesita encender DrWatson para obtener volcados para que pueda inspeccionar el bloqueo en windbg para tratar de averiguar qué le sucedió).

Para desactivar la optimización use:

#pragma optimize("g", off)

para volver a encenderlo, ya sea apagarlo o usar el caso especial

#pragma optimize("", on)

que restablece la configuración de optimización a los valores predeterminados del proyecto.

El optimizador realmente desordena su información de depuración. Existe una muy buena posibilidad de que la línea que en realidad falla en una línea cercana diferente. Incluso si el depurador le dice que la excepción está ocurriendo en la segunda mitad del operador & amp; & amp; , probablemente no lo sea.

Para diagnosticar el problema real, es posible que desee dividir la última declaración if en algo como:

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");

Si obtiene una salida de "PRUEBA 1", entonces hay algo mal con su iterador. Si obtiene una salida de "PRUEBA 2" y luego un bloqueo, entonces obviamente el error está ocurriendo en el código posterior. Si ninguno " PRUEBA 1 " ni "PRUEBA 2" se imprime y todavía se bloquea allí, entonces algo está realmente mal.

Creo que me encontré exactamente con el mismo problema.

Solo parece suceder en la versión x64 (optimización completa). Mi mapa STL se confirma vacío (tamaño () == 0), pero esta línea de código no detecta el mapa vacío y en su lugar entra en el bucle 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() );
}

Me parece un error de compilación.

  

Sí, sé que podría rodear todo con la verificación de igualdad del iterador y no es el código más agradable. El punto es que aún debería funcionar, y si eso falla, cualquier otra cosa puede hacerlo.

Por supuesto, con esa lógica no tienes opciones ... Cualquier cosa que hagas es una solución alternativa.

Creo que mi primer enfoque sería envolver las cosas en un bloque que verifique que myIt es válido:

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

Creo que está asumiendo que probablemente sea falso: que el bloqueo ocurre después de haber exitosamente verificado myIt! = m_myMap.end () & amp; & amp; myIt- > second.userStatus en la misma iteración. Apuesto a que el bloqueo ocurre inmediatamente la primera vez que se examinan estos valores. Es el optimizador lo que hace que parezca que ha borrado las dos primeras condiciones if .

Intente poner un bloque de código completamente diferente en el bucle y vea si se bloquea allí (mi apuesta es que lo haría, no creo que vea la salida de cerr inmediatamente anterior un accidente.)

// 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)

¿Por qué estás accediendo a userStatus? y foo con - > ?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top