Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème de fuites mémoire - Valgrind

    20 août 2016 à 8:53:20

    Salut !

    Je suis en train de terminer mon petit Raytracer en C, et j'en suis à une étape ou j'ai envie de corriger toutes mes fuites mémoire.

    On m'a conseillé d'utiliser Valgrind. Mais en le lançant de la manière suivante "valgrind --leak-check=full --track-origins=yes ./rt", j'obtiens plein plein de fuites qui viennent de valgrind directement je pense ...

    J'ai donc mis un "return (0)" à la première ligne de mon main() (donc mon programme se ferme directement) et voici une partie des logs: Pastebin

    Que de fuites !!

    J'ai lu comme quoi Valgrind aurait des problèmes avec OSX, mais je n'en sais pas plus. Savez vous d'où viennent ces fuites ?

    Quelqu'un aurait une solution svp? Ou un autre outil me permettant de détecter mes leaks. J'essaye d'utiliser "leaks", mais je dois lui donner un PID, ce qui signifie que je ne sais pas comment l'utiliser pleinement sur un programme qui tourne deux secondes et qui disparait de la liste des processus.

    Et je suis sous OSX El Capitan 10.11.6.

    Merci beaucoup ! :)

    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      20 août 2016 à 9:24:37

      Sans code impossible de vérifier que ce que je dis est vrai ou pas, tu devras faire la vérification toi même...

      Vérifie :

      • Que tu as bien libérer tous les tableaux dynamiques créés avec free
      • Que tu as bien mis le caractère de fin de chaîne '\0' à chaque chaîne allouée dynamiquement
      • Que tu as bien initialisé chaque tableau alloué dynamiquement
      • Que tu as bien initialisé chaque variable avant de les utiliser

      Bon courage...

      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        20 août 2016 à 9:48:36

        Bonjour,

        Quand tu utilises valgrind et que tu observe des fuites de mémoire, pour savoir à quelles lignes de ton codes elles correspondent il suffit d'utiliser l'option -g lorsque tu compile :

        gcc -g -o main main.c && valgrind --leak-check=full ./main

        Tu devrais maintenant voir à quelle ligne de ton code correspondent à peu près les erreurs. Si c'est parce que tu as oublié de libérer de la mémoire, il n'iras pas jusqu'à te dire où placer ton free() donc ne t'étonne pas si ce n'est pas aussi précis que tu le pense mais en regardant la ligne en question en général on se rend compte de notre erreur.

        • Partager sur Facebook
        • Partager sur Twitter
          20 août 2016 à 10:00:40

          J'ai donc mis un "return (0)" à la première ligne de mon main() (donc mon programme se ferme directement) et voici une partie des logs: Pastebin



          Sachant que mon programme se lance à peine, pourquoi m'affiche t-on des leaks bizarres ? Je sais très bien que mon code est rempli de leaks.

          La commande "leaks" sur mon programme m'en montre 0 (avec le return 0 dès le début). Pourquoi Valgrind m'en affiche une tonne pour une seule ligne ?

          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            20 août 2016 à 12:53:26

            Comme je l'ai dis, Valgrind ne détecte pas que cela ! Voir mon post précédent...
            • Partager sur Facebook
            • Partager sur Twitter
              20 août 2016 à 13:58:59

              Hello,

              Seybolツ a écrit:

              Sachant que mon programme se lance à peine, pourquoi m'affiche t-on des leaks bizarres ? Je sais très bien que mon code est rempli de leaks.

              La commande "leaks" sur mon programme m'en montre 0 (avec le return 0 dès le début). Pourquoi Valgrind m'en affiche une tonne pour une seule ligne ?

              Je suppose (car je ne l'ai jamais utilisé, étant sous windows) que Valgrind n'exécute pas le code, il se contente (!!!) d'analyser ton code, et donc il le parcourt entièrement, return en première ligne ou pas.

              Edgar



              • Partager sur Facebook
              • Partager sur Twitter

              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                20 août 2016 à 14:31:10

                Je viens de nettoyer mon code de A à Z. J'ai utilisé "leaks" de Xcode. Il est pas trop mal, il indique l'adresse de la fuite, la taille, mais pas vraiment autre chose d'intéressant. À coup de printf et %p, j'ai réussi à tout reboucher. Je vous montre les comparaisons de logs entre leaks et valgrind.

                Valgrind : http://pastebin.com/iC5h1ABt

                Leaks : http://pastebin.com/hgy6GM8d

                On est d'accord pour dire qu'il y a une différence. :)

                J'utilisais Valgrind avant sur les PC de mon école et il n'y avait pas de soucis si mes souvenirs sont bons. Il m'avait énormément aidé. Mais sur mon petit mac il veut pas. Quelqu'un aurait une piste ?

                Et sinon connaissez vous d'autre programme dans ce genre pour détecter les fuites mémoire ? (pour OSX)

                Merci !

                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  20 août 2016 à 15:00:04

                  #include <stdio.h>
                  #include <stdlib.h>
                  #include <string.h>
                  
                  int main ( void ) {
                  
                  	char *pointeur = NULL;
                  
                  	pointeur = malloc ( 5 * sizeof ( *pointeur ) );
                  
                  	strcpy ( pointeur , "abcd\0" );	
                  
                  	puts ( pointeur );
                  
                  	return EXIT_SUCCESS;
                  }
                  
                  clang -W -Wall -Wextra -Werror -Wpedantic -o main main.c && ./main
                  abcd
                  

                  Chouette, ça marche ! Bon allez, on passe au nettoyage.

                  clang -W -Wall -Wextra -Werror -Wpedantic -o main main.c && valgrind ./main
                  ==7398== Memcheck, a memory error detector
                  ==7398== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
                  ==7398== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
                  ==7398== Command: ./main
                  ==7398== 
                  abcd
                  ==7398== 
                  ==7398== HEAP SUMMARY:
                  ==7398==     in use at exit: 5 bytes in 1 blocks
                  ==7398==   total heap usage: 2 allocs, 1 frees, 1,029 bytes allocated
                  ==7398== 
                  ==7398== LEAK SUMMARY:
                  ==7398==    definitely lost: 5 bytes in 1 blocks
                  ==7398==    indirectly lost: 0 bytes in 0 blocks
                  ==7398==      possibly lost: 0 bytes in 0 blocks
                  ==7398==    still reachable: 0 bytes in 0 blocks
                  ==7398==         suppressed: 0 bytes in 0 blocks
                  ==7398== Rerun with --leak-check=full to see details of leaked memory
                  ==7398== 
                  ==7398== For counts of detected and suppressed errors, rerun with: -v
                  ==7398== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

                  Aie aie aie... Où est mon erreur ? Je ne vais jamais la trouver, mon code est bien trop imposant.

                  clang -W -Wall -Wextra -Werror -Wpedantic -o main main.c && valgrind --leak-check=full ./main
                  ==7407== Memcheck, a memory error detector
                  ==7407== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
                  ==7407== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
                  ==7407== Command: ./main
                  ==7407== 
                  abcd
                  ==7407== 
                  ==7407== HEAP SUMMARY:
                  ==7407==     in use at exit: 5 bytes in 1 blocks
                  ==7407==   total heap usage: 2 allocs, 1 frees, 1,029 bytes allocated
                  ==7407== 
                  ==7407== 5 bytes in 1 blocks are definitely lost in loss record 1 of 1
                  ==7407==    at 0x4C29BBE: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
                  ==7407==    by 0x4005A2: main (in /home/amin/developpement/c/Openclassrooms/main)
                  ==7407== 
                  ==7407== LEAK SUMMARY:
                  ==7407==    definitely lost: 5 bytes in 1 blocks
                  ==7407==    indirectly lost: 0 bytes in 0 blocks
                  ==7407==      possibly lost: 0 bytes in 0 blocks
                  ==7407==    still reachable: 0 bytes in 0 blocks
                  ==7407==         suppressed: 0 bytes in 0 blocks
                  ==7407== 
                  ==7407== For counts of detected and suppressed errors, rerun with: -v
                  ==7407== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

                  Ah d'accord, c'est lié à mon malloc() dans ma fonction main(). Mais où exactement ?! J'en ai des centaines !

                  clang -W -Wall -Wextra -Werror -Wpedantic -o main main.c -g && valgrind --leak-check=full ./main

                  ==7425== Memcheck, a memory error detector
                  ==7425== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
                  ==7425== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
                  ==7425== Command: ./main
                  ==7425== 
                  abcd
                  ==7425== 
                  ==7425== HEAP SUMMARY:
                  ==7425==     in use at exit: 5 bytes in 1 blocks
                  ==7425==   total heap usage: 2 allocs, 1 frees, 1,029 bytes allocated
                  ==7425== 
                  ==7425== 5 bytes in 1 blocks are definitely lost in loss record 1 of 1
                  ==7425==    at 0x4C29BBE: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
                  ==7425==    by 0x4005A2: main (main.c:9)
                  ==7425== 
                  ==7425== LEAK SUMMARY:
                  ==7425==    definitely lost: 5 bytes in 1 blocks
                  ==7425==    indirectly lost: 0 bytes in 0 blocks
                  ==7425==      possibly lost: 0 bytes in 0 blocks
                  ==7425==    still reachable: 0 bytes in 0 blocks
                  ==7425==         suppressed: 0 bytes in 0 blocks
                  ==7425== 
                  ==7425== For counts of detected and suppressed errors, rerun with: -v
                  ==7425== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

                  Ah d'accord ! À la ligne 9, j'alloue de la mémoire pour ma chaîne de caractères, sauf que je ne la libère à aucun moment ! Merci -g !

                  AminNairi a écrit:

                  [...] pour savoir à quelles lignes de ton codes elles correspondent il suffit d'utiliser l'option -g lorsque tu compile :

                  gcc -g -o main main.c && valgrind --leak-check=full ./main

                  -
                  Edité par Anonyme 20 août 2016 à 15:02:01

                  • Partager sur Facebook
                  • Partager sur Twitter
                    20 août 2016 à 16:11:22

                    Oui, merci pour l'astuce, mais je l'ai essayé, et c'est pas vraiment mieux.

                    Avec mon vrai programme : http://pastebin.com/ysJfVhP4

                    Avec un return 0 à la première ligne : http://pastebin.com/VBFK1EGq

                    Leaks est toujours ok. Aucun leak de détecté pour lui.

                    (les fonctions mlx_ sont les fonctions d'une librairie que j'utilise)

                    -
                    Edité par Seybolツ 20 août 2016 à 16:12:19

                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 août 2016 à 17:13:29

                      Bonjour,

                      Je peux comprendre ton étonnement quant au programme qui se résume à un 

                      int main(void)
                      {
                        return 0;
                      }

                      et qui malgré tout produit des logs avec valgrind. En effet, comment pourrais-tu produire des fuites de mémoire en ne faisant rien ?

                      Cela s'explique simplement en fait. Ton programme est un peu plus gros que le code ci-dessus. Il définit des fonctions qui utilisent des fonctions de bibliothèques tierces. Ces bibliothèques tierces sont utilisées lors de l'édition des liens et surtout lors du chargement du programme. Dans ton cas tu auras au minimum le chargement de la libc et de ta libmlx. Après leur chargement chargement du code spécifique d'initialisation est exécuté, et inversement du code sera aussi exécuté lors de leur déchargement.

                      C'est au moment de son initialisation que ta libmlx va allouer de l'espace mémoire qu'elle ne libérera pas correctement lors de son déchargement. C'est un comportement habituel pour les bibliothèques tierces car elles (et beaucoup de programmeurs) partent du principe qu'à la fin du programme cela ne sert à rien car toute la mémoire allouée sera de toute façon restituée sans qu'on ne fasse rien. Il y a même un argument en faveur de ce comportement : si on doit libérer énormément de blocs cela va ralentir, parfois significativement, la sortie du programme sans que cela n'apporte rien.

                      Le problème c'est que ce comportement augmente énormément les faux positifs détectés par les outils comme Valgrind. Je parle de faux positifs car même si cela reste une fuite mémoire ce n'est pas une fuite mémoire qu'il est important de combler. Ces données d'initialisation sont nécessaires tout au long de la vie du programme. Ce n'est pas le même type de «fuite» qu'une fuite qui apparaîtrait dans une boucle et qui fait effet boule de neige.

                      Valgrind reconnaît certaines de ces fuites classiques et les rend silencieuses (par exemple pour la libc) et dans ton cas, en consultant la doc valgrind, tu peux créer une liste de faux positifs pour ta bibliothèque afin de faire taire valgrind pour ne garder que l'information qui t'es utile. 

                      • Partager sur Facebook
                      • Partager sur Twitter
                      First solve the problem. Then, write the code. ~ John Johnson

                      Problème de fuites mémoire - Valgrind

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown