Partage
  • Partager sur Facebook
  • Partager sur Twitter

core dumped quand je libére l'espace alloué

    14 juin 2019 à 17:43:14

    Meilleures salutations,

    j'ai un bug pas du tout commun en C++. En effet dans une fonction de mon programme, j'ai alloué un double pointeur que j'ai utilisé comme souhaité...

    Après avoir fini, j'ai essayé de libérer l'espace mémoire qui a été déjà allouée et j'obtiens un core dumped .

    Le bug apparaît lorsque je parcours la boucle for (voir code ci-dessous) pour libérer le double pointeur matrix ie pour N=3329 il n'accède plus aux itérations qui viennent après 3311 c'est à dire un delete du 33112 éme pointeur retourne un core dumped comme le monde le code ci-après que j'ai fait pour une explication plus explicite du bug sur le vrai code qui est un gros code de calcul :

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
    
    int N=3329 ;
    int i, j;
    
      int **matrix = new int *[N];
      for ( i=0;i<N;i++)
        {
          matrix[i] = new int [N];
        }
    
    
      // Initialisatiion
      for ( i = 0; i < N; i++)
      {
        for ( j = 0; j < N; j++)
        {
            matrix[i][j] = 0;
        }
    
        }
        
      for (i=0; i<N; i++)
        {
          delete[] matrix[i];
        }
    	  delete[] matrix;
    	  
    	  
    }
    

    PS: en affichant la valeur de N avant la désallocation, j'ai bel et bien N=3329.

    -
    Edité par madj_rek 14 juin 2019 à 20:28:18

    • Partager sur Facebook
    • Partager sur Twitter
      14 juin 2019 à 18:02:18

      MadiopLO1 a écrit:

      j'ai un bug pas du tout commun en C++ (...)j'ai alloué un double pointeur 

      Je dirais au contraire que c'est très commun d'avoir des bugs quand on joue avec les pointeurs...

      Mais bon, a priori, je vois pas d'erreur dans ton code. (Autre que le problème récurrent de libération de la mémoire en cas d'exception). Pas de raison d'avoir un crash. (Sauf si tu n'as pas assez de memoire, tu utilises plus de 170 Mo en memoire)

      • Partager sur Facebook
      • Partager sur Twitter
        14 juin 2019 à 18:32:30

        gbdivers a écrit:

        MadiopLO1 a écrit:

        j'ai un bug pas du tout commun en C++ (...)j'ai alloué un double pointeur 

        Je dirais au contraire que c'est très commun d'avoir des bugs quand on joue avec les pointeurs...

        Mais bon, a priori, je vois pas d'erreur dans ton code. (Autre que le problème récurrent de libération de la mémoire en cas d'exception). Pas de raison d'avoir un crash. (Sauf si tu n'as pas assez de memoire, tu utilises plus de 170 Mo en memoire)

        Je dirais aussi mais celui-là franchement il est pas commun.

        Assez de mémoire ? non j'ai pas vérifié mais je pense que cela doit dépasser 170 Mo car c'est un code de calcul. Comment puis-je checker la valeur exacte de mémoire utilisée par le programme  svp ?

        Je pense pas que cela provient de la taille de la mémoire parce que j'ai fait un run avec N>3329 et cela marchait bien.

        -
        Edité par madj_rek 14 juin 2019 à 20:12:08

        • Partager sur Facebook
        • Partager sur Twitter
          17 juin 2019 à 11:05:14

          >N>3329 et cela marchait bien

          Cela s'appelle "tomber en marche" et c'est pas bon signe.

          Le plus simple, c'est de trouver une séquence d'action/jeu de données qui reproduise le problème 100ù des cas (de préférence assez rapidement) et d'utiliser un débogueur pour comprendre le problème.

          Faire une connerie avec la mémoire ne veut pas dire un core dump automatique, malheureusement.

          Les coredump sont fait pour une analyse post-mortem avec un débogueur, donc pensez à vous en servir.

          P.S.: les pointeurs nus, c'est CACA, et des doubles, c'est bien pire.

          • Partager sur Facebook
          • Partager sur Twitter
          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
            17 juin 2019 à 14:04:40

            J'ai rarement vu autant de new dans un code C++.

            Pourquoi ne pas faire un tableau linéarisé de N * N avec un vrai conteneur (std::array dans ton cas ou std::vector au cas où N est variable à l'exécution).

            • Partager sur Facebook
            • Partager sur Twitter

            git is great because Linus did it, mercurial is better because he didn't.

              18 juin 2019 à 11:01:19

              markand a écrit:

              J'ai rarement vu autant de new dans un code C++.

              Pourquoi ne pas faire un tableau linéarisé de N * N avec un vrai conteneur (std::array dans ton cas ou std::vector au cas où N est variable à l'exécution).


              C'est pas un problème du moment qu'on les libère après adéquatement.
              • Partager sur Facebook
              • Partager sur Twitter
                18 juin 2019 à 12:10:44

                >C'est pas un problème du moment qu'on les libère après adéquatement.

                C'est impossible avec un langage à exception comme le C++ et même avec d'autres langages comme le C dans un système générant des SEH (Windows, Linux sur Intel, MacOS, etc...)

                Le C++ offre tout ce qu'il faut pour ne pas galérer, utilisez les et laissez tomber ces pointeurs nus tout foireux.

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  18 juin 2019 à 12:38:50

                  Salut ! 

                  Un code a l'ancienne. Mais semble correct pour autant. 

                  Par contre, ça plante avec juste le bout de code que tu as mis ? Ou alors quand tu fais un traitement au milieu ?

                  Car un delete qui plante, c'est bien souvent quand on a fait un débordement en amont : et dans la seule partie que tu montres, il n'y a pas de débordement.

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                    18 juin 2019 à 14:04:40

                    MadiopLO1 a écrit:

                    markand a écrit:

                    J'ai rarement vu autant de new dans un code C++.

                    Pourquoi ne pas faire un tableau linéarisé de N * N avec un vrai conteneur (std::array dans ton cas ou std::vector au cas où N est variable à l'exécution).


                    C'est pas un problème du moment qu'on les libère après adéquatement.

                    Ce qui n'est pas le cas dans ton code. Si un de tes new plante dans ta boucle, tu as une partie de la mémoire partiellement allouée et l'autre non. c.f mes VDDs.

                    -
                    Edité par markand 18 juin 2019 à 14:05:31

                    • Partager sur Facebook
                    • Partager sur Twitter

                    git is great because Linus did it, mercurial is better because he didn't.

                      18 juin 2019 à 14:45:10

                      markand a écrit:

                      MadiopLO1 a écrit:

                      markand a écrit:

                      J'ai rarement vu autant de new dans un code C++.

                      Pourquoi ne pas faire un tableau linéarisé de N * N avec un vrai conteneur (std::array dans ton cas ou std::vector au cas où N est variable à l'exécution).


                      C'est pas un problème du moment qu'on les libère après adéquatement.

                      Ce qui n'est pas le cas dans ton code. Si un de tes new plante dans ta boucle, tu as une partie de la mémoire partiellement allouée et l'autre non. c.f mes VDDs.

                      -
                      Edité par markand il y a 33 minutes

                      L'initialisation se fait bien dans mon code c'est au niveau de la dé-allocation que je rencontre ce problème. Je pense comme la si bien dit @Fvirtman, j'ai du faire un dépassement sans faire exprès dans le code et par la suite y'a des blocs de mémoire qui ont sauté.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 juin 2019 à 15:32:13

                        Utilisez le coredump pour voir où VOUS avez merdé avec vos pointeurs nus.

                        Vous vous prenez la tête parce que vous faites du C++ comme si c'était du C des années 70, faut arrêter de se prendre la tête sur ces conneries.

                        Utilisez des pointeurs intelligents, les bibliothèques spécialisées dans les calculs, voir dans les calculs matriciels et ne pas réinventer une roue carré.

                        Si vous êtes masochiste mais pas suicidaire, vous pouvez activer les options de votre compilateur pour vous simplifier le débogage de genre de problème de mémoire (fuite, écrasement, sanitazer, canaries, etc...).

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                          18 juin 2019 à 16:06:03

                          Salut,

                          MadiopLO1 a écrit:

                          C'est pas un problème du moment qu'on les libère après adéquatement.

                          C'est justement tout le problème : il n'y a jamais moyen de savoir si les pointeurs nus sont libérés de manière adéquate en C++, à moins de créer une capsule RAII pour chaque allocation effectuée, car, comme l'a si bien fait remarquer Bacelar, C++ est un langage à exceptions ...

                          Reprenons ton exemple de base:

                          int main()
                          {
                           
                          int N=3329 ;
                          int i, j;
                           
                            int **matrix = new int *[N]; // (1)
                            for ( i=0;i<N;i++)
                              {
                                matrix[i] = new int [N];  // (2)
                              }

                          New peut lancer une exception à peu près n'importe quand, si le système d'exploitation décide de ne pas fournir l'espace mémoire demandé.

                          Cela signifie qu'une exception peut être lancée en (1), ce qui serait encore "la meilleure des choses" qui pourraient nous arriver, car, étant donné que ce serait la première allocation dynamique qui foire, le fait de lancer une exception mettrait, purement et simplement, fin à l'application, sans avoir besoin de veiller à libérer correctement la mémoire pour quoi que ce soit (vu qu'il n'y aura pas  eu de mémoire allouée)

                          Mais cela signifie aussi qu'une exception peut être lancée en (2), et ce, pour n'importe quelle valeur de i comprise entre 0 et N (exclus),selon la logique.  Et là, les choses deviennent compliquées parce que:

                          il faut forcément libérer la mémoire allouée en (1), mais, avant de pouvoir le faire, il faut aussi et surtout libérer la mémoire qui a été allouée par l'ensemble des passages en (2) qui ont réussi, c'est à dire, pour tous les passages en (2) compris entre 0 et i (exclus, vu que celui-là a échoué, si une exception a été lancée)

                          Il y a une circonstance qui pourrait te sauver de la misère si l'exception survient en (2), c'est que tu as déclaré ta variable i en dehors de la boucle, mais, pour que cela puisse te sauver, il eu fallu que tu gère correctement les exceptions si elles venaient à survenir, ce qui n'est pas le cas.

                          Pour gérer correctement les exceptions, nous pourrions, du fait que tu as déclaré i en dehors de la boucle, considérer qu'en corrigeant le code pour lui donner une forme proche de

                          int main()
                          {
                           
                          int N=3329 ;
                          int i, j;
                           try{
                                int **matrix = new int *[N]; // (1)
                                for ( i=0;i<N;i++)
                                {
                                    matrix[i] = new int [N];  // (2)
                                }
                              }
                           catch(std::except & e){
                               for(j = 0;j<i;++j)
                                   delete[] matrix[j];
                               delete matrix;
                               throw e;
                           }  

                          pourrait suffir, mais non!  matrix est déclaré dans la portée du try, et, du coup, la variable en question est oubliée ... lorsque la fermeture de l'accolade correspondante est atteinte, ce qui fait que matrix est inconnue dans le bloc catch.

                          Deuxième essais:

                          int main()
                          {
                           
                          int N=3329 ;
                          int i, j;
                          int ** matrix;
                           try{
                                matrix = new int *[N]; // (1)
                                for ( i=0;i<N;i++)
                                {
                                    matrix[i] = new int [N];  // (2)
                                }
                              }
                           catch(std::except & e){
                               for(j = 0;j<i;++j)
                                   delete[] matrix[j];
                               delete matrix;
                               throw e;
                           } 

                          Ah, c'est mieux: matrix étant déclaré avant le bloc try, la variable sera connue dans le bloc catch :D  On pourrait donc croire que notre problème est résolu, mais non!

                          En effet, la valeur de i est indéfinie pour toutes les instructions qui précède la ligne for(i = 0; ...) :'( Si bien que, avant que tu n'arrive à  cette ligne, i peut valoir ... à peu près n'importe quoi: 0, avec un peu de chance, ou  peut-être 1 234 567 ou pire encore : -456

                          Oui, mais.  Et, de toutes manières, le fait de boucler entre 0 et i qui ne vaut "on ne sait pas quoi" risque particulièrement de nous  emmener "dans les choux".

                          Et, quand bien même "tout se passerait bien", et il n'y aurait pas d'exception lancée ni en (1) ni en (2) (ce qui devrait par chance être le cas le plus fréquent), il faudrait savoir ce que tu vas faire avec ta matrice.  Sais tu, juste pour l'exemple, qu'un code aussi simple que std::cout<<matrix[i][j]; pourrait parfaitement lancer une exception ?

                          Alors, au vu de tout ce que je viens de t'expliquer : es tu vraiment sur de libérer correctement tes pointeurs ??

                          -
                          Edité par koala01 18 juin 2019 à 16:06:23

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait

                          core dumped quand je libére l'espace alloué

                          × 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