2012-03-01 7 views
6

editar: Lo he descubierto con la ayuda de comentaristas. Para responder a la pregunta planteada en mi título: No, no es corrupción de la pila, su gdb informa los valores incorrectos. El programa realmente se comporta como se esperaba y tiene el puntero derecho this. El comportamiento real de errores que me impulsó a publicar esta pregunta probablemente no esté relacionado con el problema que describo aquí.El constructor llamó con el puntero "this" incorrecto. ¿Esta pila es corrupta?

Primera advertencia. Creo que este es un problema de corrupción de memoria, y normalmente no esperaría una respuesta, excepto para "verificar su código a fondo", pero he visto este comportamiento aparecer repetidamente y esperaba que algunos de ustedes tuvieran una idea del problema y de cómo puede encontrar su fuente

Actualmente estoy implementando un análisis estático de intervalos que rastrea el posible rango de variables en un programa C. El constructor de copia para mi base de intervalo de clase se ve así:

itvt::itvt(const itvt& i) 
    : _i(i.type == INTBV ? new intbv_intervalt(i.i()) : NULL), 
    _f(i.type == FLOAT ? new float_intervalt(i.f()) : NULL), 
    type(i.type), other_bottom(i.other_bottom) 
{ } 

Ahora, me encontré con un error de corrupción de memoria y logró remontar hasta el siguiente fragmento de código:

itvt itvt::get_split(bool le) const 
{ 
    itvt result(*this); 
    [...] 
} 

El uso de GDB, me encontrar que no parece que la llamada al constructor para construir el "número" objeto:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) n 
519 if(is_singleton() || is_bot()) 
(gdb) print result 
$3 = { 
    _i = { 
    _M_ptr = 0x7fff5fbfe100 
    }, 
    _f = { 
    _M_ptr = 0x7fff5fbfed60 
    }, 
    type = 1606410016, 
    other_bottom = 255 
} 
(gdb) print *this 
$4 = { 
    _i = { 
    _M_ptr = 0x1020833a0 
    }, 
    _f = { 
    _M_ptr = 0x0 
    }, 
    type = itvt::INTBV, 
    other_bottom = false 
} 

Mirando más profundamente, me parece que dentro del constructor de copia, el puntero "this" apunta al objeto equivocado:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) print &result 
$5 = (itvt *) 0x7fff5fbfdee0 
(gdb) s  
itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
500  type(i.type), other_bottom(i.other_bottom) 
(gdb) print this 
$6 = (itvt * const) 0x7fff5fbfdf80 

Desde "número" se asigna en la pila en la dirección 0x7fff5fbfdee0, yo esperaría que el "este" puntero dentro del constructor de copia para que apunte a la misma dirección. En cambio, apunta a 0x7fff5fbfdf80.

Parece que el constructor de copias está inicializando algo, pero no el objeto "resultado" en la pila en la que se llama. De hecho, puedo acceder a la memoria en la cual el constructor inicializa perfectamente bien:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) s  
itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
500  type(i.type), other_bottom(i.other_bottom) 
(gdb) finish 
Run till exit from #0 itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
itvt::get_split (this=0x1016af560, le=false) at itv.cpp:519 
519 if(is_singleton() || is_bot()) 
(gdb) print *((const itvt*) (0x7fff5fbfdf80)) 
$7 = { 
    _i = { 
    _M_ptr = 0x1016b6d10 
    }, 
    _f = { 
    _M_ptr = 0x0 
    }, 
    type = itvt::INTBV, 
    other_bottom = false 
} 

Mi primera pregunta: ¿Puede el hecho de que las "este" puntero apunta al objeto equivocado explicarse como un comportamiento normal? Parece un extraño problema de corrupción de memoria, pero tal vez me falta algo.

Estoy compilando con g ++ y "-O0 -ggdb" flags e hice una recompilación nueva de todo por cierto. Aquí está mi g ++ versión:

[email protected] ai$ g++ --version 
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) 
Copyright (C) 2007 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

Mi segunda pregunta: Si se trata de una corrupción de memoria, ¿tiene algún consejo sobre cómo puedo rastrear la fuente. Por lo general, sigo esos problemas hasta su causa raíz usando gdb, pero no sé dónde buscar ahora.

Esta no es la primera vez que encuentro este comportamiento específico. Lo he visto suceder al investigar los errores de otras personas. En realidad, nunca me las arreglé para abordarlo directamente, simplemente dejó de suceder o al menos fue un problema visible después de algún otro cambio de código. Esto me lleva a creer que tal vez sea solo un extraño artefacto de mirar la pila usando gdb.

Agradezco cualquier consejo o idea que pueda ofrecer.

edición: Éstos son es el fragmento correspondiente de la clase ITVT:

class itvt 
{ 
protected: 
    typedef std::auto_ptr<intbv_intervalt> iptrt; 
    typedef std::auto_ptr<float_intervalt> fptrt; 
    iptrt _i; 
    fptrt _f; 
public: 
    typedef enum {INTBV, FLOAT, OTHER} itv_typet; 
    itv_typet type; 

    bool other_bottom; 

    //copy constr 
    itvt(const itvt& i); 

    inline intbv_intervalt& i() { return *_i; } 
    inline float_intervalt& f() { return *_f; } 
    inline const intbv_intervalt& i() const { return *_i; } 
    inline const float_intervalt& f() const { return *_f; } 

    itvt get_split(bool le) const; 

    [...] 
}; 
+0

Gracias por la información, eso es interesante para mí en otro contexto. No, la clase itvt es completamente aburrida/no virtual. No hay virtualidad o herencia involucrada en itvt o sus miembros. – leo

+1

Solo una pregunta: es su versión de 'gdb' actualizada. He visto casos en los que el uso de una versión anterior de 'gdb' con una versión más reciente del compilador hace que' gdb' muestre las cosas incorrectas. (A priori, esto solo debería ser un problema cuando se cambian las versiones principales: cuando apareció g ++ 4.0.0 por primera vez, gdb tardó un tiempo en ponerse al día. Pero nunca se sabe). –

+2

Un segundo punto es que cuando lo haces 's 'para entrar en una función, algunos depuradores (no estoy seguro acerca de gdb --- he visto esto con VS, sin embargo) no entran lo suficiente en la función para el marco de pila local que se va a configurar. Esto da como resultado que todos los valores sean incorrectos (cuando el depurador los ve). –

Respuesta

4

Segunda pregunta: utilizar valgrind, que es realmente lo que necesita aquí. Realiza un seguimiento de cada asignación/free, y te dice si intentas utilizar la memoria liberada, así como muchas otras cosas. Te mostrará una corrupción de memoria.

2

Lo he descubierto con la ayuda de comentaristas: Parece que gdb no dice la verdad, (posiblemente debido a una versión antigua de gdb). El programa realmente se comporta como se esperaba.

El comportamiento actual de errores que me llevó a examinar el problema no tenía relación con la inicialización del objeto.

Cuestiones relacionadas