Pregunta

Esto es bastante extraño para mí, pero recibo un error de segmentación inesperado y aleatorio cuando inicio mi programa.Algunas veces funciona, otras falla.El depurador de Dev-C++ me señala una línea del archivo:stl_construct.h

/**
   * @if maint
   * Constructs an object in existing memory by invoking an allocated
   * object's constructor with an initializer.
   * @endif
   */
  template<typename _T1, typename _T2>
    inline void
    _Construct(_T1* __p, const _T2& __value)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_]allocator::construct
     -> ::new(static_cast<void*>(__p)) _T1(__value);
    }

Por cierto, estoy usando mucho el STL.¿Qué debo hacer para detectar el origen del segfault?¿Existe alguna herramienta que pueda ayudar?¿Cuáles son las razones que pueden provocar fallos aleatorios como este?

Editar:

Mi programa cuenta alrededor de 5000 líneas de código.No sé qué fragmento de código tengo que mostrar para obtener ayuda ya que no tengo idea del origen del problema, todo lo que obtuve del depurador es que tiene que ver con el STL.

Editar:

Me mude a Code::Blocks Ahora, aquí está la pila de llamadas:

#0 00464635 std::_Construct<std::pair<double const, int>, std::pair<double const, int> >(__p=0xb543e8, __value=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_construct.h:81)
#1 00462306 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_create_node(this=0x406fe50, __x=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:367)
#2 00461DA7 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_clone_node(this=0x406fe50, __x=0x0) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:379)
#3 004625C6 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_copy(this=0x406fe50, __x=0x0, __p=0x406fe54) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:1029)
#4 00462A9D std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_Rb_tree(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:559)
#5 0045A928 std::map<double, int, std::less<double>, std::allocator<std::pair<double const, int> > >::map(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_map.h:166)
#6 0040B7E2 VehicleManager::get_vehicles_distances(this=0xb59a50) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/VehicleManager.cpp:232)
#7 00407BDA Supervisor::IsMergeInstruction(id_vehicle=1) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:77)
#8 00408430 CheckingInstructionsThread(arg=0x476100) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:264)
#9 00413950 _glfwNewThread@4() (??:??)
#10 75A24911    KERNEL32!AcquireSRWLockExclusive() (C:\Windows\system32\kernel32.dll:??)
#11 00476100    std::__ioinit() (??:??)
#12 0406FFD4    ??() (??:??)
#13 76E5E4B6    ntdll!RtlInitializeNtUserPfn() (C:\Windows\system32\ntdll.dll:??)
#14 00476100    std::__ioinit() (??:??)
#15 70266582    ??() (??:??)
#16 00000000    ??() (??:??)

Algunas precisiones más:

1/ Es una aplicación multiproceso.2/ El método :get_vehicles_distances();devuelve un mapa.3/ Es posible que el mapa no esté inicializado en el momento en que IsMergeInstruction() lo llama;

Editar:

Aparentemente la línea que está causando el error de segmentación es:

vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

Donde distancias_vehículos_ es el Mapa.Esta línea es parte del método:Administrador de vehículos::MoveAllVehicles();

void VehicleManager::MoveAllVehicles() {

     vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

     vector<Vehicle>::iterator iter_end = VehicleManager::vehicles_.end();
     for(vector<Vehicle>::iterator iter = VehicleManager::vehicles_.begin();
     iter != iter_end; ++iter) {

          (*iter).MoveVehicle();

          vehicles_distances_[(*iter).get_vec_vehicle_position().y] = (*iter).get_id_vehicle();

     }

}

Qué hay de malo con eso ?

Editar:

Intenté usar map::clear();como reemplazo de map::erase();¡pero ocurre el mismo problema!

Editar:

Creo que lo entiendo...Un hilo está intentando hacer uso de vehículos_distancias_ mientras se borra.(?)

Editar:

¡Problema resuelto!Entonces venía de map::erase();como se esperaba.Solucioné el problema creando otra variable de mapa donde el par <key, value> Se invirtió para poder actualizar el mapa.(ya que la clave que necesito es la distancia, y la distancia no es única ya que cambia cada vez, ¡pero id_vehicle es única!).Al final simplemente tomé ese mapa, invertí el <key, value> nuevamente y lo transfirió al mapa original que puede ser redeclarado en cada ciclo...

Gracias a todos !

¿Fue útil?

Solución

Primero, por el amor de todo lo que es, bueno, adorable, no uses Dev-C++.Ojalá supiera cómo la gente sigue topándose con ese pedazo de basura.No ha sido mantenido por años, e incluso cuando se le dio mantenimiento, seguía siendo una basura con errores que carecía de una funcionalidad muy básica.Deshazte de él y opta por una de las innumerables alternativas gratuitas mejores.

Ahora, a tu pregunta:Su programa falla aleatoriamente porque ha hecho algo ilegal antes.No hagas eso.;)

Si su programa escribe fuera de los límites en alguna parte, puede pasar cualquier cosa.Es posible que llegue a una página no asignada, en cuyo caso obtendrá un error de segmentación.O podría llegar a datos no utilizados en una página asignada a su proceso, en cuyo caso no tendrá ningún efecto práctico (a menos que se inicialice correctamente después, sobrescribiendo su primera escritura ilegal y luego intente leer de ella). , esperando que el valor original (no válido) siga ahí.O podría afectar a datos que realmente están en uso, en cuyo caso obtendrá errores más adelante, cuando el programa intente leer esos datos.

Existen prácticamente los mismos escenarios al leer datos.Puede tener suerte y obtener un error de segmentación inmediatamente, o puede acceder a la memoria no utilizada y no inicializada, y leer datos basura (lo que probablemente provocará un error más adelante, cuando se utilicen esos datos), o puede leer desde direcciones de memoria que están ya en uso (lo que también le dará basura).

Entonces sí, estos errores son difíciles de encontrar.El mejor consejo que puedo dar es 1) esparcir afirmaciones por todo el código para garantizar que se mantengan las invariantes básicas y 2) recorrer el programa y, en cada paso, verificar que no esté leyendo ni escribiendo en direcciones que no lo hagan. No te pertenezco.

MSVC tiene una opción SCL segura habilitada de forma predeterminada que realizará la verificación de límites en el código STL, lo que puede ayudar a detectar errores como este.

Creo que GCC tiene una opción para hacer algo similar (pero no está habilitada de forma predeterminada).

Los fallos de segmento son desagradables.Una vez que las personas han sido picadas por un error como este varias veces, tienden a volverse mucho más disciplinadas para evitar el acceso a la memoria fuera de los límites.:)

Otros consejos

Usted puede tratar Valgrind como una manera de ayudar a encontrar el problema. Teniendo en cuenta la línea que usted ha puesto en la pregunta, tendría que adivinar que ha corrompido o bien del montón, o si tiene un problema de pila.

La pregunta obvia sería "lo que es _p". En el depurador usted debe ser capaz de mirar a la pila de llamadas. Siga _p de nuevo a su origen. Confirmar su tamaño correcto, que no se ha eliminado, y que de hecho existe.

Si eso no es fácil, siempre hay los métodos de fuerza bruta de comentar a cabo (se sospecha) código aleatorio hasta que funcione o ir hacia atrás y se diferencian contra un conocido, copia de trabajo.

Esto es muy vaga, por lo que es casi imposible de responder. Una sugerencia obvia sería la de comprobar si está inicializar todas las variables. Algunos compiladores cero fuera de su materia sin inicializar en depurar y no hacerlo en la liberación, por ejemplo, lo que lleva a resultados aleatorios e inesperados.

Puede utilizar _CrtSetDbgFlag() en el comienzo de su programa para habilitar algunas opciones montón de depuración. Ver también El CRT montón de depuración . Esto puede ayudar a localizar donde está haciendo cosas malas con la memoria. Está disponible en tiempo de ejecución C de Microsoft, que los enlaces compilador MinGW contra por defecto. Si usted está utilizando en su lugar el tiempo de ejecución C de GNU, entonces no va a ser capaz de seguir este camino.

Es mucho más probable que sea en su código que en stl_construct.h El problema. Estoy asumiendo que el archivo es parte de la distribución de STL para Dev-C ++. El fallo de segmentación puede estar ocurriendo en el código que se crea una instancia utilizando las plantillas en stl_construct.h, pero la causa raíz del problema va a estar en otra parte. Me gustaría tratar de resolver esto consiguiendo el seguimiento de pila en el momento del accidente. Para cada función en el seguimiento de la pila (especialmente los que están recién escritos), trata de examinar el código y buscar los siguientes tipos de errores posibles:

  • variables no inicializadas (especialmente índices utilizados para acceso a matriz)
  • Memoria utilizada después de que haya sido liberado o eliminado.
  • acceso de matriz fuera de los límites de la matriz
  • La asignación de memoria que se utiliza sin ser controlado por NULL (no es un problema si utiliza nueva porque eso no devuelve NULL, se produce una excepción)

Su descripción, y la pila de llamadas, sugieren que el programa se bloquea durante la inicialización de variables estáticas. Este es un error común de C ++:. No hay una forma sencilla de controlar el orden de inicialización de las variables estáticas

Por ejemplo, el programa puede tener foo objeto que depende de bar objeto; pero puede ser que el programa está llamando al constructor para foo antes de que se construye bar. Eso sería malo, y podrían provocar que la clase de problema que usted describe. (Se CheckingInstructionsThread una variable estática que genera un subproceso? Eso podría ser el problema allí mismo.)

Para solucionar este problema, puede que tenga que mirar a través de los archivos .cpp de su programa para las variables estáticas (incluyendo la estática de clase y globales), especialmente aquellos que son de algún tipo de clase. Puede o no puede ayudar a modificar sus constructores para escribir algunos rastros a stderr; fprintf utilizar en lugar de cerr si lo hace.

Editar : Si no está seguro de si esto tiene algo que ver con la estática, trate de poner una línea como esta en el comienzo de main():

 fprintf(stderr, "main() entered\n");

Esto no descarta la inicialización estática como la causa del problema; incluso si no lo hace estructuras accidente antes de main(), aún se podía tener de datos que se establecieron de forma incorrecta. Pero, si nunca llega a la fprintf, a continuación, sabe que la inicialización estática es la causa.

¿Qué le dice el seguimiento de la pila después de ejecutar el depurador con el archivo de la base? Ejecutar GDB de la forma habitual gdb a.out

A continuación, examine el archivo de núcleo

  

núcleo a.out.core

Y echar un vistazo a la pila

  

bt

Esto es más probablemente relacionado con iterador invalidado - buscar los lugares donde se iterar sobre los contenedores y / o mantienen iteradores en contenedores y retirar / insertar elementos al mismo tiempo, Opiniones y como todo el mundo observó -. Utilizar una llamada- apilar para encontrar el punto exacto.

Lo primero que hay que hacer cuando terminas en código que se ha probado a fondo, que no es el suyo va a la pila de llamadas hasta que terminan en su propio código, donde se encuentra la información que causó este problema a suceder.

En la llamada pila de la ubicación más importante a buscar es en su código (la persona que llama) y los parámetros que se pasan a la función que llama (el llamado).

Sin esta información, no podemos ayudarle más. ; -)

Más información sobre violaciones de segmento: http://en.wikipedia.org/wiki/Segmentation_fault
(Debe lectura, ver también los enlaces "Ver también" y "enlaces externos")

Los mapas no son muy amigable thread. Si realiza operaciones de correlación de código de hilo que realmente necesita para bloquear todos los accesos a ese mapa y darse cuenta de cualquier iteradores se puede llevar a cabo podría ser invalidado.

Se ve como una función peligrosa:)

Una cosa que me striked sin embargo. ¿A dónde va la memoria asignada? Intuitivamente me gustaría tener un puntero a un puntero como primer argumento y luego eliminar la referencia. De esta manera:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1** __p, const _T2& __value)
    {

       ::new(static_cast<void*>(*__p)) _T1(__value);
    }

Alternativamente, una referencia a un puntero:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1*& __p, const _T2& __value)
    {

       ::new(static_cast<void*>(__p)) _T1(__value);
    }

El depurador debería dejarte ir hasta la pila de llamadas. De esta manera usted debería ser capaz de ver el lugar en su propio código que está causando el fallo seg.

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