señalando el mensaje valgrind "salto o movimiento condicional depende de los valores no inicializados"

166

Así que he estado recibiendo un mensaje misterioso de valores no inicializados de valgrind y ha sido un misterio saber de dónde se originó el valor malo.

Parece que valgrind muestra el lugar donde el valor unitario termina siendo utilizado, pero no el origen del valor no inicializado.

==11366== Conditional jump or move depends on uninitialised value(s)
==11366==    at 0x43CAE4F: __printf_fp (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43C6563: vfprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43EAC03: vsnprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x42D475B: (within /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E2C9B: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E31B4: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42EE56F: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
==11366==    by 0x810B9F1: Snake::Snake::update() (snake.cpp:257)
==11366==    by 0x81113C1: SnakeApp::updateState() (snakeapp.cpp:224)
==11366==    by 0x8120351: RoenGL::updateState() (roengl.cpp:1180)
==11366==    by 0x81E87D9: Roensachs::update() (rs.cpp:321)

Como se puede ver, se vuelve bastante críptico ... especialmente porque cuando dice Class :: MethodX, a veces apunta directamente a ostream, etc. ¿Quizás esto se deba a la optimización?

==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)

Así. ¿Se me escapa algo? ¿Cuál es la mejor manera de atrapar los malos valores sin tener que recurrir al trabajo detectivesco de impresión súper larga?

Actualizar:

Descubrí lo que estaba mal, pero lo extraño es que valgrind no lo informó cuando se usó el valor incorrecto por primera vez. Fue utilizado en una función de multiplicación:

movespeed = stat.speedfactor * speedfac * currentbendfactor.val;

Donde speedfac era un flotador unitializado. Sin embargo, en ese momento no se informó y no es hasta que se imprima el valor que obtengo el error. ¿Existe una configuración para valgrind para cambiar este comportamiento?

kamziro
fuente

Respuestas:

230

Use la opción valgrind --track-origins=yespara que rastree el origen de los valores no inicializados. Esto lo hará más lento y tomará más memoria, pero puede ser muy útil si necesita rastrear el origen de un valor no inicializado.

Actualización: con respecto al punto en el que se informa el valor no inicializado, el manual de valgrind establece :

Es importante comprender que su programa puede copiar datos basura (sin inicializar) tanto como quiera. Memcheck observa esto y realiza un seguimiento de los datos, pero no se queja. Se emite una queja solo cuando su programa intenta hacer uso de datos no inicializados de una manera que podría afectar el comportamiento visible externamente de su programa.

De las preguntas frecuentes de Valgrind :

En cuanto al informe ansioso de copias de valores de memoria no inicializados, esto se ha sugerido varias veces. Desafortunadamente, casi todos los programas copian legítimamente valores de memoria no inicializados (porque los compiladores rellenan las estructuras para preservar la alineación) y la comprobación ansiosa conduce a cientos de falsos positivos. Por lo tanto, Memcheck no admite comprobaciones ansiosas en este momento.

mark4o
fuente
1
¿Cuál es la versión mínima de valgrind para usar esta función? Estoy usando 3.3.0 y no parece que me guste la opción.
Robert S. Barnes
8
@Robert: --track-origins se agregó en valgrind 3.4.0
mark4o
20

Lo que esto significa es que está intentando imprimir / generar un valor que al menos no está inicializado parcialmente. ¿Puedes reducirlo para saber exactamente qué valor es? Después de eso, rastrea tu código para ver dónde se está inicializando. Lo más probable es que veas que no se está inicializando por completo.

Si necesita más ayuda, publicar las secciones relevantes del código fuente puede permitir que alguien le ofrezca más orientación.

EDITAR

Veo que has encontrado el problema. Tenga en cuenta que valgrind observa el salto o movimiento condicional en función de variables unitarias. Lo que eso significa es que solo emitirá una advertencia si la ejecución del programa se modifica debido al valor no inicializado (es decir, el programa toma una rama diferente en una declaración if, por ejemplo). Como la aritmética real no implicaba un salto o movimiento condicional, valgrind no le advirtió de eso. En su lugar, propagó el estado "no inicializado" al resultado de la declaración que lo utilizó.

Puede parecer contradictorio que no le advierte de inmediato, pero como señaló mark4o , lo hace porque los valores no inicializados se utilizan en C todo el tiempo (ejemplos: relleno en estructuras, la realloc()llamada, etc.) por lo que esas advertencias no serían Muy útil debido a la frecuencia de falsos positivos.

RarrRarrRarr
fuente
Gracias. Me acabo de enterar de lo que estaba mal, pero lo extraño es, valgrind no informó de la cosa de valor unitialised hasta que fue usado en otra parte ..
kamziro
Eso es intencional. Si solo copiar o pasar valores no inicializados causó un informe de error, los obtendría todo el tiempo del relleno en las estructuras.
mark4o