163 votes

localisation du message valgrind "conditional jump or move depends on uninitialized value(s)" (saut ou déplacement conditionnel dépend de valeurs non initialisées)

J'ai reçu de mystérieux messages de valgrind concernant des valeurs non initialisées, et l'origine de cette mauvaise valeur est un véritable mystère.

Il semble que valgrind montre 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 lorsqu'il est dit par Class::MethodX, il pointe parfois directement vers ostream, etc. Peut-être est-ce dû à l'optimisation ?

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

Juste comme ça. Il y a quelque chose qui m'échappe ? Quelle est la meilleure façon d'attraper les mauvaises valeurs sans avoir à recourir à un travail de détective printf super long ?

Mise à jour :

J'ai trouvé ce qui n'allait pas, mais ce qui est étrange, c'est que valgrind ne l'a pas signalé lorsque la mauvaise valeur a été utilisée pour la première fois. Elle était utilisée dans une fonction de multiplication :

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

Où speedfac était un flottant unitialisé. Cependant, à ce moment-là, il n'a pas été signalé et ce n'est que lorsque la valeur doit être imprimée que j'obtiens l'erreur . Existe-t-il un paramètre pour valgrind permettant de modifier ce comportement ?

226voto

mark4o Points 20472

Utiliser l'option valgrind --track-origins=yes pour qu'il suive l'origine des valeurs non initialisées. Cela le rendra plus lent et prendra plus de mémoire, mais peut être très utile si vous avez besoin de retrouver l'origine d'une valeur non initialisée.

Mise à jour : Concernant le moment où la valeur non initialisée est signalée, le manuel de valgrind indique :

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

De la Valgrind FAQ :

Quant à la notification rapide des copies de valeurs de mémoire non initialisées, elle a été suggérée à plusieurs reprises. Malheureusement, presque tous les programmes copient légitimement des valeurs de mémoire non initialisées (parce que les compilateurs remplissent les structures pour préserver l'alignement) et la vérification rapide conduit à des centaines de faux positifs. Par conséquent, Memcheck ne prend pas en charge le contrôle empressé pour le moment.

20voto

RarrRarrRarr Points 1538

Cela signifie que vous essayez d'imprimer/sortir une valeur qui est au moins partiellement non initialisée. Pouvez-vous préciser cette valeur afin de savoir exactement de quelle valeur il s'agit ? Ensuite, suivez votre code pour voir où il est initialisé. Il y a de fortes chances pour que vous constatiez que l'initialisation n'est pas complète.

Si vous avez besoin de plus d'aide, la publication des sections pertinentes du code source pourrait permettre à quelqu'un d'offrir plus de conseils.

EDIT

Je vois que vous avez trouvé le problème. Notez que valgrind surveille Saut ou déplacement conditionnel basé sur des variables unitialisées. Cela signifie qu'il n'émettra un avertissement que si l'exécution du programme est modifiée à cause de la valeur non initialisée (par exemple, le programme prend une branche différente dans une instruction if). Puisque l'arithmétique réelle n'implique pas de saut ou de déplacement conditionnel, valgrind ne vous a pas averti de cela. Au lieu de cela, il a propagé le statut "non initialisé" au résultat de l'instruction qui l'a utilisé.

Le fait qu'il ne vous avertisse pas immédiatement peut sembler contre-intuitif, mais en tant que mark4o a fait remarquer, il le fait parce que des valeurs non initialisées sont utilisées en C tout le temps (exemples : le remplissage dans les structures, la fonction realloc() ), de sorte que ces avertissements ne seraient pas très utiles en raison de la fréquence des faux positifs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X