web-dev-qa-db-fra.com

localiser "le saut ou le déplacement conditionnel dépend d'une ou plusieurs valeurs non initialisées"

Donc, j'ai reçu un message mystérieux de valeurs non initialisées de Valgrind et cela a été tout à fait mystérieux quant à l'origine de la mauvaise valeur.

Il semble que valgrind indique l'endroit où la valeur unitialisée finit par être utilisée, mais pas l'origine de la valeur non initialisée.

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

Comme on peut le voir, cela devient assez cryptique .. surtout parce que quand on dit par Class :: MethodX, ça pointe parfois directement sur ostream etc. C'est peut-être dû à une optimisation?

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

Juste comme ça. Y a-t-il quelque chose qui me manque? Quel est le meilleur moyen d’attraper de mauvaises valeurs sans avoir à recourir à un travail de détective très long pour printf?

Mise à jour:

J'ai découvert ce qui n'allait pas, mais ce qui est étrange, c'est que valgrind ne l'a pas signalé lors de la première utilisation de cette valeur. Il a été utilisé dans une fonction de multiplication:

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

Où speedfac était un flotteur unitialisé. Cependant, à ce moment-là, l'erreur n'a pas été signalée et ce n'est pas avant que la valeur soit imprimée. Existe-t-il un paramètre permettant à Valgrind de modifier ce comportement?

155
kamziro

Utilisez l’option valgrind --track-origins=yes pour qu’elle suive l’origine des valeurs non initialisées. Cela ralentira le processus et nécessitera plus de mémoire, mais peut s'avérer très utile si vous devez rechercher l'origine d'une valeur non initialisée.

Mise à jour: En ce qui concerne le point où la valeur non initialisée est signalée, les états du manuel valgrind :

Il est important de comprendre que votre programme peut copier autant de données qu'il le souhaite autour de données indésirables (non initialisées). Memcheck observe ceci et garde une trace des données, mais ne se plaint pas. Une plainte est émise uniquement lorsque votre programme tente d'utiliser des données non initialisées de manière à affecter le comportement de votre programme visible de l'extérieur.

De la Valgrind FAQ :

En ce qui concerne les rapports enthousiastes de copies de valeurs de mémoire non initialisées, cela a été suggéré plusieurs fois. Malheureusement, presque tous les programmes copient légitimement des valeurs de mémoire non initialisées (car les compilateurs complètent les structures pour préserver l'alignement) et une vérification minutieuse conduit à des centaines de faux positifs. Par conséquent, Memcheck ne prend pas en charge la vérification rapide pour le moment.

220
mark4o

Cela signifie que vous essayez d'imprimer/de générer une valeur au moins partiellement non initialisée. Pouvez-vous la réduire afin de savoir exactement quelle est la valeur? Après cela, tracez votre code pour voir où il est initialisé. Les chances sont, vous verrez que ce n'est pas complètement initialisé.

Si vous avez besoin d’aide supplémentaire, la publication des sections pertinentes du code source peut permettre à une personne d’offrir davantage de conseils.

EDIT

Je vois que vous avez trouvé le problème. Notez que valgrind surveille le saut ou le déplacement conditionnel en fonction de variables unitialisées. Cela signifie que cela ne produira un avertissement que si l'exécution du programme est modifiée en raison de la valeur non initialisée (c'est-à-dire que le programme prend une branche différente dans une instruction if, par exemple). Comme l'arithmétique réelle ne comportait pas de saut conditionnel, Valgrind ne vous en avait pas averti. Au lieu de cela, il a propagé le statut "non initialisé" au résultat de la déclaration qui l'a utilisé.

Cela peut sembler contre-intuitif de ne pas vous avertir immédiatement, mais comme mark4o l'a souligné, c'est parce que les valeurs non initialisées sont utilisées en C tout le temps (exemples: remplissage dans les structures, la realloc() call, etc.) afin que ces avertissements ne soient pas très utiles en raison de la fausse fréquence positive.

20
RarrRarrRarr