IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Conditional jump or move depends on uninitialised value(s). Est-ce grave ?


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 23
    Points
    23
    Par défaut Conditional jump or move depends on uninitialised value(s). Est-ce grave ?
    Bonsoir,

    Je malloc un char* dans une fonction puis je le remplit dans une autre fonction, ducoup, valgrind me bombarde de
    Conditional jump or move depends on uninitialised value(s)
    Ma question est : est-ce que c'est grave et surtout est-ce qu'il y a un risque de faire planter le programme ?

    PS : Je free absolument tout je n'ai aucune fuite de mémoire

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Ça veut surtout dire que tu as un fonctionnement indéterminé et un check qui dépend de ce qui traînait dans la mémoire avait auparavant.
    Faudrait voir le vrai code pour ça, un malloc ou free n'a quasi rien à voir ici.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 23
    Points
    23
    Par défaut
    en gros le code source donne ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    while (condition) {
            str1 = realloc(str1, nb1);
            //fill_str(str1, nb1);
            str2 = realloc(str2, nb2);
            //fill_str(rstr2, nb2);
           //je manipule str1 et str2 à l'aide d'autres fonctions 
    }
    free(str1)
    free(str2)
    fill_str est une fonction qui va remplir l'intégralité de la string (jusqu'à l'index souhaité) par des '\0' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void fill_str(char *str, int len)
    {
        for (int i = 0; i < len; i++)
            str[i] = '\0';
    }
    dans l'exemple, j'ai mis en commentaire l'appel à la fonction fill_str afin d'avoir le warning de valgrind :

    Conditional jump or move depends on uninitialised value(s)

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Mattness69 Voir le message
    en gros le code source donne ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    while (condition) {
            str1 = realloc(str1, nb1);
            //fill_str(str1, nb1);
            str2 = realloc(str2, nb2);
            //fill_str(rstr2, nb2);
           //je manipule str1 et str2 à l'aide d'autres fonctions 
    }
    free(str1)
    free(str2)
    Il faut impérativement que "str1" et "str2" aient été initialisés. Soit avec un malloc, soit avec NULL.

    Citation Envoyé par Mattness69 Voir le message
    fill_str est une fonction qui va remplir l'intégralité de la string (jusqu'à l'index souhaité) par des '\0' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void fill_str(char *str, int len)
    {
        for (int i = 0; i < len; i++)
            str[i] = '\0';
    }
    Pour aller plus vite je serais passé directement par le pointeur "str" ce qui évite une indirection => for (int i=0; i < len; i++) {*str=0; str++;}.
    Mais sinon pourquoi ne pas utiliser memset() qui est justement faite pour ça...?

    Citation Envoyé par Mattness69 Voir le message
    Ma question est : est-ce que c'est grave et surtout est-ce qu'il y a un risque de faire planter le programme ?
    On peut résumer les soucis liés aux variables en deux axiomes élémentaires
    1. ne jamais lire une variable sans l'avoir remplie au préalable
    2. ne jamais remplir deux fois une variable sans la lire entre temps

    Le second axiome peut être plus ou moins négligé et n'aura aucun effet néfaste si c'est le cas (au pire, remplir plusieurs fois la même variable ralentira juste le code sans le corrompre). Il m'arrive d'ailleurs parfois d'initialiser un truc tout en sachant que je pourrai peut-être y re-écrire plus tard sans l'avoir forcément lu entre temps.
    Mais le premier reste incontournable. Tu ne pourras jamais avoir un résultat correct si tu ne l'as pas d'abord calculé et éventuellement stocké. Et tu ne pourras jamais calculer le bon résultat si tu n'initialises pas d'abord les variables servant à le calculer. "0" est peut-être l'élément neutre de l'addition mais il est implicite en mathématique et doit être explicité en C.

    Et dans ce que tu me montres, fill_str() ne viole aucun de ces deux axiomes. Seul reste l'éventuel souci de "str1" et "str2" non initialisés (et bien évidemment aussi "nb1" et "nb2" cela va sans dire)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 23
    Points
    23
    Par défaut
    J'initialise bien str1, str2, nb1 et nb2.

    Effectivement, je ne m'étais jamais intéressé à la fonction memset() merci pour ton aide.

    Il y a cependant quelque chose que je n'ai pas bien compris

    Pour aller plus vite je serais passé directement par le pointeur "str" ce qui évite une indirection => for (int i=0; i < len; i++) {*str=0; str++;}.
    Cela représente quoi selon une indirection dans cette exemple ?
    Nous n'avons probablement pas la même idée en tête.

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mattness69 Voir le message
    J'initialise bien str1, str2, nb1 et nb2.
    Ca pourrait être plus subtil.
    Par exemple ceci
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    initialisation str1 et str2
    while(truc_a_la_con) {
    	while (condition) {
    		str1 = realloc(str1, nb1);
    		//fill_str(str1, nb1);
    		str2 = realloc(str2, nb2);
    		//fill_str(rstr2, nb2);
    		//je manipule str1 et str2 à l'aide d'autres fonctions 
    	}
    	free(str1);
    	free(str2);
    }
    Ca fonctionnera à la première itération puis partira ensuite en torche parce que les free() auront rendu "str1" et "str2" totalement invalides aux realloc suivants. Nul doute que valgrind verrait ce genre de souci.

    Citation Envoyé par Mattness69 Voir le message
    Cela représente quoi selon une indirection dans cette exemple ?
    Nous n'avons probablement pas la même idée en tête.
    Une indirection c'est chaque fois qu'on écrit t[x] ("t" étant un tableau quelconque). Le compilateur le traduit par
    • déplacement au début du tableau
    • décalage de "x" positions


    Imagine par exemple tout le travail qui sera généré dans ces simples lignes
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int tab[]={1, 2, 3, 4, 5};
    for (i=0; i < 5; i++)
    	printf("Le carré de %d est %d\n", tab[i], tab[i] * tab[i]);
    Et c'est encore pire quand on utilise un tableau de structures au lieu d'un tableau de types élémentaires...

    Si on utilise un pointeur déjà placé à la bonne case, ces deux opérations disparaissent.
    Imagine alors ce que tu gagnes en modifiant le code ainsi
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int tab[]={1, 2, 3, 4, 5};
    int *pt;
    for (i=0, pt=tab; i < 5; i++, pt++)
    	printf("Le carré de %d est %d\n", *pt, (*pt) * (*pt));
    C'est pas super compliqué à transformer. C'est ce que j'ai fait avec ta fonction et là c'était encore plus facile vu que j'avais déjà le pointeur disponible dans le paramètre reçu. J'ai même été tenté d'écrire for (i=0; i < len; i++, *(str++)=0); mais mis à part rendre le code juste plus compliqué à relire, on ne gagne rien et ça fait juste ressortir mon manque de mémoire des 14 priorités des opérateurs du C vu que j'ai mis des parenthèses dont je ne suis pas certain qu'elles soient nécessaires.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Méfiance vis-à-vis de ce genre "d'optimisation du pauvre".

    Par exemple, GCC 9 génère le même code assembleur pour les 2 fonctions suivantes en -O2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdlib.h>
     
    void fill_naive(char* str, const size_t len) {
        for (int i = 0; i < len; i++) {
            str[i] = '\0';
        }
    }
     
    void fill_educated(char* str, const size_t len) {
        for (int i = 0; i < len; i++) {
            *str=0;
            str++;
        }
    }
    En -O1, il y un MOV en plus pour la version naive, mais qui optimise en O1 ?

    En -O3, les 2 boucles sont remplacées par....... un appel à memset()

    On en revient à l'éternelle règle : écris du code intelligent, simple, efficace, dont on comprend facilement l'objectif, et fais travailler ton compilateur à ta place. Et j'ai bien dit d'écrire du code intelligent, il ne s'agit pas de faire n'importe quoi. Et je ne dis pas ce que ce genre de code est bête, c'est juste qu'il ne remplace pas de manière géniale un code pourri.

    Pour voir l'assembleur, c'est ici : https://godbolt.org/z/vvCb7K

  8. #8
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par Bktero Voir le message
    En -O1, il y un MOV en plus pour la version naive, mais qui optimise en O1 ?
    Je précise juste au cas où que je suis d'accord avec toi , et que j’amène juste une précision pour dire que le code assembleur est juste un aperçu , mais jamais une bonne façon de savoir qu'est qui est le plus optimisé et surtout pas en regardant une instruction en plus ou en moins.
    Les compilateurs actuelle aura souvent tendance de deplier un peu la boucle qui augmente un peu le nombre d'instructions , mais permet d'éviter pas mal de test.

    Le proc actuelle Intel est capable d'exécuter 5 instructions en même temps , du coup dans un cas extrême on peut avoir deux code où :
    -un ferait 10 instructions et 5 qui s’exécuterait en même temps (donc 2 cycles)
    -et inversement avoir 8 instructions et 2 qui s’exécute en même temps (et donc 4 cycles)

    Bref pour dire quelque chose de bateau , la plus grosse optimisation sera d'un point de vue algo , le code assembleur peut être un aperçu , mais le code asm peut aussi être "surprenant" d'un point de vue perf (dans le sens où celui qu'on penserait qui s’exécuterait le plus rapidement est le plus long).
    C'est un peu le souci des procs actuelle , difficile à prédire au cycle près si on prend tout en compte.

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Pour voir l'assembleur, c'est ici : https://godbolt.org/z/vvCb7K
    Fatale erreur que tu aies donné ce lien. Comme quoi ça tient à peu de choses. Tu ne l'aurais pas mis je t'aurais fait confiance, sachant que les optimiseurs d'aujourd'hui arrivent à faire des miracles (arriver à voir que la fonction en question se résume à memset() là je dis ).
    Mais voilà, il y était et tel l'enfant qui met les doigts dans la prise, j'ai cliqué !!!
    Et pour me rendre compte que tu avais compilé ça en C++
    Compile en C et tu verras un MOV et aussi n MOVSX en plus.

    Citation Envoyé par Bktero Voir le message
    Méfiance vis-à-vis de ce genre "d'optimisation du pauvre".
    Whaaa le sarcasme Comme je me sens trop atteint par ta flèche qui m'atteint en plein coeur
    Qu'est-ce que ça fait de remplacer une indirection par un pointeur si tu peux le faire ? Dans le pire des cas ça optimisera pareil et dans le meilleur ça optimisera en plus.
    Et puis le C c'est pas que sur du cray en intel muticore quantique qui va te faire du "-O8000". C'est aussi sur du composant 16k qui va pleurer sa mère si tu ne l'aides pas un peu.
    Encore évidemment faut-il maitriser le pointeur...

    Citation Envoyé par Bktero Voir le message
    Ecris du code intelligent, simple, efficace, dont on comprend facilement l'objectif, et fais travailler ton compilateur à ta place.
    Ecris du code intelligent, simple, efficace, dont on comprend facilement l'objectif, et si tu peux te faire aider du compilateur pourquoi pas, mais n'en fais pas ta béquille
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2021
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2021
    Messages : 1
    Points : 4
    Points
    4
    Par défaut inconditional jump or move depends on uninitialised value(s)
    Bonsoir à vous je sais que je suis un petit peu en retard mais je pense pouvoir apporter une réponse à ton probleme car moi aussi j'avais exactement le même problème, je vais te montrer une capture d'écran de mon érreur et une autre de ma corréction ainsi tu pourras voir le probleme.

    mon but était de parcourir et de copier les contenus de ma chaine str dans mon tab (qui est un double pointeur) tant que je n'aurais pas rencontrer de séparateur (les separateur present dans str etait contenu dans la chaine charset). lorsque je rencontrais un séparateur, je descendais de une ligne dans mon tab et je copiais ainsi la suite de mon str.

    donc voici le probleme que j'avais au depart :
    (tu peut commencer à lire à partir de la ligne 24)
    Nom : Capture d'écran de 2021-03-01 22-19-08.png
Affichages : 711
Taille : 186,7 Ko


    si tu observe mon code tu remarqueras que à la ligne 46 de l'image si dessous j'ai rajouter quelque chose.
    Nom : Capture d'écran de 2021-03-01 22-19-24.png
Affichages : 699
Taille : 149,0 Ko
    enfaite le probleme se trouvais dans l'initalisation de la derniere case de mon double tableau tab, car lorsque j'avais fini de parcourir str, j'arretais aussi de copier vers tab et je quittais aussitôt la boucle sans avoir mis un '\0' a la derniere case de mon tab, donc si tu à le meme message relis bien ton code pour verifier que tu n'a pas oublier d'initialiser.

Discussions similaires

  1. Réponses: 1
    Dernier message: 26/06/2018, 01h17
  2. Réponses: 2
    Dernier message: 29/01/2017, 22h49
  3. strtok_r: Conditional jump or move depends on uninitialised value
    Par ikuzar dans le forum Bibliothèque standard
    Réponses: 2
    Dernier message: 19/03/2013, 15h36
  4. Réponses: 8
    Dernier message: 17/05/2010, 11h34
  5. "Use of uninitialised value"
    Par |PaRa-BoL dans le forum Bibliothèque standard
    Réponses: 5
    Dernier message: 12/02/2009, 22h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo