Forum Programmation.c ma j'galère sur un simple free sur un string

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
0
28
août
2019

Salut à tous,
j'ai acheté le livre de Christophe Blaess ( en personne ) sur la programmation système.
Je suis tombé sur un truc intéressant page 695-696-697 du bouquin dans le chapitre 23 intitulé "Communication classique entre processus" concernant une "possibilité rarement proposée par les shell". Selon moi, à première vue, il s'agissait seulement de ce à quoi pourrait faire face un simple fichier ".sh". Mais en me penchant un peu sur la question, je me suis rendu compte des facultés d'un tel algorithme. Pipé des commandes pré-enregistrées dans une bdd au format ".json", créées à partir d'autres programmes, afin de les faire communiquer etc…
Tu rends compte? Faire fonctionner la modularité du "c", en "c" même, ce sur un système basé sur ce procédé, j'ai nommé LINUX…
Je vous présente, ci-après, comment je procède. En attendant voici le code disposé dans trois fichier:

  • fichier "process.h":

        #ifndef PROCESS_H
        #define PROCESS_H
    
        #include<stdio.h>
        #include<stdlib.h>
        #include<unistd.h>
        #include<sys/stat.h>
        #include<string.h>
        #include<errno.h>
        #include<sys/wait.h>
        #include<sys/types.h>
        #include"file.h"
    
        typedef struct {
                char ***commands;
                int **args;
            char **result;
                int len;
            int size;
            int execcount;
        } process_datas;
    
        int process_pipe(char** commands, int fd[2], pid_t *son);
        int process_popen(char ** result, char** commands, int args, int *size);
        int process_finished(pid_t pid);
        int process_datas_internal(process_datas *p, char **result, int *size, int i);
        int process_append_cmd(char * param, process_datas * datas, int new_command);
        int process_exec(process_datas *p);
        int process_datas_destroy(process_datas *p);
        int process_datas_init(process_datas *p);
    
        #endif
    
  • fichier "process.c":

    #define _GNU_SOURCE
    #include"process.h"
    #include"file.h"
    
    extern char **environ;
    
    int process_pipe(char** commands, int fd[2], pid_t *son)
    {
    
        int tube_1[2];
            int tube_2[2];
            if ((pipe(tube_1) != 0) || (pipe(tube_2) != 0))
                    return EXIT_FAILURE;
    
            switch(*son = fork())
            {
                    case -1:
                close(tube_1[0]); close(tube_1[1]);
                            close(tube_2[0]); close(tube_2[1]);
                            fprintf(stderr, "fail to fork in process_pipe\n");
                return errno;
                    break;
                    case 0: ;
                            setpgid(0, 0);
                            close(tube_1[1]);
                            close(tube_2[0]);
                dup2(tube_1[0], STDIN_FILENO);
                            dup2(tube_2[1], STDOUT_FILENO);
                            execve(commands[0], commands, environ);
                            perror("execve in process_pipe");
                            return errno;
                    break;
                    default: ;
                             setpgid(*son, *son);
                            close(tube_1[0]);
                            close(tube_2[1]);
                            fd[0] = tube_2[0];
                            fd[1] = tube_1[1];
            }
        return EXIT_SUCCESS;
    }
    
    int process_popen(char ** result, char** commands, int args, int *size)
    {
            FILE* fd;
        int len = 0;
        for(int i = 0; i < args - 1; i++)
        {
            len += strlen(commands[i]) + 2;
        }
            char *command = malloc(len);
        char *c = command;
        for(int i = 0; i < args - 1; i++)
        {
            sprintf(command, "%s ", commands[i]);
            command += strlen(commands[i]) + 1;
        }
            if((fd = popen(c, "r")) != NULL)
            {
            if(file_fgetsn(result, fd, size))
            {
                free(command - strlen(c));
                pclose(fd);
                perror("fgetsn in process_popen");
                return EXIT_FAILURE;
            }
            }else{
            free(command - strlen(c));
                    perror("popen in process_popen");
                    return EXIT_FAILURE;
            }
        free(command - strlen(c));
            pclose(fd);
            return EXIT_SUCCESS;
    }
    int process_append_cmd(char *param, process_datas *datas, int new_command)
    {
        if(!new_command)
        {
            if(datas->size)
            {
                int args = datas->args[datas->size - 1][1]++;
                if(args > datas->args[datas->size - 1][0])
                {
                    datas->args[datas->size - 1][0] += 1;
                    datas->commands[datas->size - 1] = (char**)realloc(datas->commands[datas->size - 1],
                    datas->args[datas->size - 1][0] * sizeof(char*));
                }
                datas->commands[datas->size - 1][datas->args[datas->size - 1][1] - 1] = (char*) NULL;
            }
            datas->size++;
            if(!datas->len)
            {
                datas->len = datas->size;
                datas->args = (int **) calloc(datas->len, sizeof(int*));
                datas->args[0] = (int*) calloc(2, sizeof(int));
                datas->args[0][0] = 7;
                datas->args[0][1] = 1;
                datas->commands = (char***) calloc(datas->len, sizeof(char**));
                datas->commands[0] = (char**) calloc(7, sizeof(char*));
            }else
            if(datas->size > datas->len)
            {
                datas->len = datas->size;
                datas->args = (int **)realloc(datas->args, datas->len * sizeof(int*));
                datas->args[datas->size - 1] = (int *)calloc(2, sizeof(int));
                datas->args[datas->size - 1][0] = 7;
                datas->args[datas->size - 1][1] = 1;
                datas->commands = (char***) realloc(datas->commands, datas->len * sizeof(char**));
                datas->commands[datas->size - 1] = (char **) calloc(7, sizeof(char*));
            }
        }else{
            int args = datas->args[datas->size - 1][1]++;
            if(!(args - datas->args[datas->size - 1][0]))
            {
                datas->args[datas->size - 1][0] += 7;
                datas->commands[datas->size - 1] = (char**) realloc(datas->commands[datas->size - 1], 
                        datas->args[datas->size - 1][0] * sizeof(char*));
            }
        }
        datas->commands[datas->size - 1][datas->args[datas->size - 1][1] - 1] = strdup((char *)param);
    
        return EXIT_SUCCESS;
    }
    
    int process_finished(pid_t pid)
    {
            errno = 0;
            int status;
            while(1)
            {
                    usleep(2000);
                    pid_t check;
                    if((check = waitpid(pid, &status, WNOHANG|WUNTRACED)) > 0)
                    {
                            if(WIFEXITED(status))
                            {
                                    printf("%ld terminated successfully : %s\n", (long) pid, "signal OK !");
                                    return EXIT_SUCCESS;
                            }else if(WIFSIGNALED(status))
                            {
                                    printf("%ld terminated by signal : %s\n", (long) pid, strsignal(WTERMSIG(status)));
                            }else if(WIFSTOPPED(status))
                            {
                                    printf("%ld stopped by signal : %s\n", (long) pid, strsignal(WSTOPSIG(status)));
                            }else if(WIFCONTINUED(status))
                            {
                                    printf("%ld continued\n", (long) pid);
                            }
                    }else if(check == -1){
                            return errno;
                    }
            }
            return EXIT_FAILURE;
    }
    
    int process_exec(process_datas *p)
    {
        int ret = 0;
        char * result = NULL;
        int size= 0;
        int args = p->args[p->size - 1][1]++;
        if(args > p->args[p->size - 1][0])
        {
            p->args[p->size - 1][0] += 1;
            p->commands[p->size - 1] =
                realloc(p->commands[p->size - 1],
                    p->args[p->size - 1][0] * sizeof(char*));
        }
        p->commands[p->size - 1][p->args[p->size - 1][1] - 1] = (char*) NULL;
        p->execcount++;
        p->result = realloc(p->result, p->execcount * sizeof(char*));
    
        if((ret = process_datas_internal(p, &result, &size, 0)) == EXIT_FAILURE)
        {
            free(result);
            fprintf(stderr, "Error in first command in process_exec: not / or bad internal process");
            return EXIT_FAILURE;
        }else if(ret == 254 || ret == 255 || ret == EXIT_SUCCESS){
            if((ret = process_popen(&result, p->commands[0], p->args[0][1], &size)) == EXIT_FAILURE)
            {
                if(result != NULL)
                    free(result);
                fprintf(stderr, "Error in first command in process_exec from process_popen\n");
                return EXIT_FAILURE;
            }
        }
        if(p->size == 1)
        {
            p->result[p->execcount - 1] = strdup(result);
            free(result);
            process_datas_init(p);
            return EXIT_SUCCESS;
        }
            int tube[2];
        pid_t son;
        int error;
            for(int i = 1; i < p->size; i++)
            {
            if((ret = process_datas_internal(p, &result, &size, i)) == EXIT_FAILURE)
            {
                free(result);
                fprintf(stderr, "Bad internal process");
                return EXIT_FAILURE;
            }else if(ret != EXIT_SUCCESS && ( i + 1 ) < p->size)
                ++i;
            if((ret = process_pipe(p->commands[i], tube, &son))) {
                free(result);
                fprintf(stderr, "fail to process_pipe in process_exec");
                return errno;
    
            }
            if(fd_writen(tube[1], result, strlen(result), 1))
            {
                free(result);
                fprintf(stderr, "fail to write in fd in process_exec");
                return EXIT_FAILURE;
            }
            close(tube[1]);
            if((error = process_finished(son)) != EXIT_SUCCESS)
            {
                free(result);
                return error;
            }
            if(fd_readn(&result, tube[0], &size))
            {
                free(result);
                fprintf(stderr, "fail to read from fd in process_exec");
                return EXIT_FAILURE;
            }
            close(tube[0]);
        }
        p->result[p->execcount - 1] = strdup(result);
        free(result);
        process_datas_init(p);
    
        return EXIT_SUCCESS;
    
    }
    
    int process_datas_internal(process_datas *p, char **result, int *size, int i)
    {
        if(!strcmp(p->commands[i][0], "file"))
        {
            FILE *f = fopen(p->commands[i][1], "w+");
            if (f == NULL)
            {
                free(*result);
                fprintf(stderr, "Error opening file in process_exec\n");
                return EXIT_FAILURE;
            }
    
            fprintf(f, *result);
    
            fclose(f);
            return 254;
        }else if(!strcmp(p->commands[i][0], "cd")){
            chdir(p->commands[i][1]);
            return 255;
        }else if(!strcmp(p->commands[i][0], "concat")){
            int len = 0;
            for(int l = 1; l < p->args[i][1] - 1; l++)
                len += strlen(p->commands[i][l]) + 2;
            if(*size < len) 
                *result = calloc(len, sizeof(char));
            for(int l = 1; l < p->args[i][1] - 1; l++)
            {
                if(l == 1)
                    strcpy(*result, p->commands[i][l]);
                else
                    strcat(*result, p->commands[i][l]);
            }
            return 256;
        }
        return EXIT_SUCCESS;
    }
    
    int process_datas_init(process_datas *p)
    {
        for(int i = 0; i < p->size; i++)
        {
            for(int j = 0; j < p->args[i][1]; j++)
            {
                free(p->commands[i][j]);
                p->commands[i][j] = NULL;
            }
            p->args[i][1] = 1;
        }
        p->size = 0;
    
        return EXIT_SUCCESS;
    
    }
    
    int process_datas_destroy(process_datas *p)
    {
        for(int i = 0; i < p->len; i++)
        {
            for(int j = 0; j < p->args[i][1]; j++)
            {
                if(p->commands[i][j] != NULL)
                {
                    free(p->commands[i][j]);
                    p->commands[i][j] = NULL;
                }
            }
            free(p->commands[i]);
            p->commands[i] = NULL;
        }
        free(p->commands);
        p->commands = NULL;
    
            for(int i = 0; i < p->len; i++)
            {
                free(p->args[i]);
                p->args[i] = NULL;
            }
            free(p->args);
        p->args = NULL;
        p->len = 0;
        p->size = 0;
        for(int i = 0; i < p->execcount; i++)
        {
            free(p->result[i]);
            p->result[i] = NULL;
        }
        free(p->result);
        p->result = NULL;
        p->execcount = 0;
        return EXIT_SUCCESS;
    }
    
  • fichier "file.c"

            #include"file.h"
    
            int file_read(char **result, int *size)
            {
                    FILE * file = (void*) NULL;
                struct stat status;
                char * content = (void*) NULL;
    
                    if (stat(*result, & status) != 0) {
                    perror("stat");
                    return EXIT_FAILURE;
                }
                if ((content = malloc(status.st_size)) == NULL) {
                    perror("malloc");
                    return EXIT_FAILURE;
                }
                if ((file = fopen(*result, "r")) == NULL) {
                    free(content);
                    perror("fopen");
                    return EXIT_FAILURE;
                }
                if ((signed int)fread(content, 1, status.st_size, file) != status.st_size) {
                    free(content);
                    perror("fread");
                    return EXIT_FAILURE;
                }
    
                    *size = status.st_size;
                    *result = content;
                fclose(file);
                return EXIT_SUCCESS;
            }
    
            int file_fgetsn(char **result, FILE* fd, int *size)
            {
                int i = 0, j = 0;
                char buffer[64] = {'\0'};
                if(!(*size >= 128))
                {
                    j = 128;
                    *result = calloc(j, sizeof(char));
                }else{
                    j = *size;
                }
                if(*result)
                {
                    while(fgets(buffer, 64, fd) != NULL)
                    {
                        if(!i)
                            strcpy(*result, buffer);
                        else
                            strcat(*result, buffer);
                        i += strlen(buffer);
                        if((j - i) < 64)
                        {
                            j = i + 128;
                            *result = realloc(*result, j);
                            if(*result == NULL)
                            {
                                perror("realloc in file_fgetsn");
                                return EXIT_FAILURE;
                            }
                        }
                    }
                }else{
                    perror("malloc in file_fgetsn");
                    return EXIT_FAILURE;
                }
                *size = j;
    
                return EXIT_SUCCESS;
            }
    
            int fd_writen(const int sd, const char * b, const size_t s, const int retry_on_interrupt)
            {
                size_t n = s;
                while (0 < n)
                {
                    ssize_t result = write(sd, b, n);
                    if (-1 == result)
                    {
                        if ((retry_on_interrupt && (errno == EINTR)) || (errno == EWOULDBLOCK) || (errno == EAGAIN))
                        {
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    n -= result;
                    b += result;
                }
    
                if(0 < n){
                    perror("write in fd_writen");
                    return EXIT_FAILURE;
                }else{  
                    return EXIT_SUCCESS;
                }
            }
    
            int fd_readn(char** result, int fd, int *size)
            {
                int m = 0; 
                char buffer[2] = {'\0'};
                while(read(fd, buffer, sizeof(char)))
                {
                    if(!m)
                        strcpy(*result, buffer);
                    else
                        strcat(*result, buffer);
                    m += strlen(buffer);
                    if((*size - m) < 64)
                    {
                        *size = m + 128;
                        *result = realloc(*result, *size);
                    }
                    if(*result == NULL)
                    {
                        perror("realloc in file_read");
                        return EXIT_FAILURE;
                    }
                }
    
                return EXIT_SUCCESS;
            }
    

exemple "test.c":

            #define _DEFAULT_SOURCE
            #include<stdio.h>
            #include<stdlib.h>
            #include<string.h>
            #include<unistd.h>
            #include"process.h"

            int main(int argc, char **argv)
            {
                int ret;
                process_datas p = {NULL, NULL, NULL, 0, 0, 0};
                char *cwd = calloc(1,256);
                getcwd(cwd, 256);
                process_append_cmd("concat", &p, 0);
                process_append_cmd("j'adore ", &p, 1);
                process_append_cmd("windows", &p, 1);
                process_append_cmd("/bin/sed", &p, 0);
                process_append_cmd("-es;windows;linux;g", &p, 1);

                if(!(ret = process_exec(&p)))
                {
                    printf("%s\n", p.result[0]);
                    process_append_cmd("concat", &p, 0);
                    process_append_cmd(p.result[0], &p, 1);
                    process_append_cmd(" avec", &p, 1);
                    process_append_cmd(" enthousiasme !!", &p, 1);

                    if(!(ret = process_exec(&p)))
                    {
                        printf("%s\n", p.result[1]);
                    }else{
                        free(cwd);
                        process_datas_destroy(&p);
                        fprintf(stderr, "failed: %s \n", strerror(ret));
                        exit(EXIT_FAILURE);
                    }
                }else{
                    free(cwd);
                    process_datas_destroy(&p);
                    fprintf(stderr, "failed: %s \n", strerror(ret));
                    exit(EXIT_FAILURE);
                }

                process_datas_destroy(&p);
                free(cwd);
                return EXIT_SUCCESS;
            }

Alors je sais que c'est un peu imbuvable question longueur, mais imaginez le potentiel en récursif…

Alors mon problème, qui ne représente rien face à la tâche à accomplir, est que je n'arrive pas à libérer les variables concaténées ( d'où l'utilisation qui fonctionne dans le programme "test.c" ci-dessus ) lorsqu'il s'agit de simples caractères au niveau de l'appel à "process_datas_init" dans "process_exec".

Si quelqu'un pouvait m'aider cela me permettrait de gagner du temps sur mon projet qui est largement entamé ( sous d'autres perspectives ) et en même temps de rendre hommage à un édifice du monde linuxien.

Merci d'avance.

PS: L'interface finale est destinée à être programmée en ncurses

  • # Isoler le code problématique

    Posté par  . Évalué à 9.

    Est-ce que tu pourrais isoler et reproduire ton problème dans un nombre minimal de ligne?

    C'est assez courrant de faire ça avant de demander de l'aide sur un forum. Ça aiderait les gens à comprendre ton problème.

    • [^] # Re: Isoler le code problématique

      Posté par  . Évalué à 1. Dernière modification le 29 août 2019 à 20:00.

      Quand tu galères sur les strings et tu te fais tailler un short ^^

      Oui moi aussi quand j'ai vu la longueur du code j'ai décidé de pas lire. Et de laisser un commentaire à la con !

  • # Reallocation sans free ?

    Posté par  . Évalué à 7. Dernière modification le 28 août 2019 à 23:00.

    Je suis tombé sur un truc intéressant intitulé "Communication classique entre processus"
    concernant une "possibilité rarement proposée par les shell".

    Et, de quoi s'agit-il ?

    Alors je sais que c'est un peu imbuvable question longueur,

    Oui. Essayez de garder le même style. Ici, la position des {, par exemple, est aléatoire.

    utilisez des goto pour la gestion d'erreur avec libération de ressources, ce sera plus lisible et vous risquerez moins d'en oublier une.

    Alors mon problème, est que je n'arrive pas à libérer les variables concaténées ( d'où l'utilisation qui fonctionne dans le programme "test.c" ci-dessus ) lorsqu'il s'agit de simples caractères au niveau de l'appel à "process_datas_init" dans "process_exec".

    Préférez strncat et strncpy qui vous éviterons des ennuis, d'autant que vous recalculez la longueur juste avant.

    Je sens un problème dans process_datas_internal.

    Je suppose que result a été alloué ailleurs et passé en paramètre. Dans ce cas, à quoi rime le calloc ? Il provoque une nouvelle allocation de result sans que l'ancien ne soit libéré et n'a pas de sens avec une taille de 1 (sizeof(char)) . Ce n'est pas plutôt un realloc que vous vouliez faire ?

    Au passage, plutôt que de faire des if dans les for sur la variable de loop. Traitez les séparément:

    /* l=1*/
    strcpy(*result, p->commands[i][1]);
    /* l=2.. */
    for(int l=2;l < p->args[i][1] - 1; l++){
                    strcat(*result, p->commands[i][l]);
    }

    Pourquoi passer size par référence alors que vous ne l'utilisez que par variable ?

    • [^] # Re: Reallocation sans free ?

      Posté par  . Évalué à 2.

      Merci David pour toutes ces suggestions.
      ```

      Je suis tombé sur un truc intéressant intitulé "Communication classique entre processus"
      concernant une "possibilité rarement proposée par les shell".
      

      Il s'agit tout simplement de l'emploi du pipe, ce afin de rediriger l'entrée ET la sortie ( c'est là la nouveauté ) d'une sous routine de mon programme père. Ce système permet l'exécution de sous-routines à la chaîne, et donc de créer un programme composé uniquement de sous-routines - que j'appellerais modules du programme. En concaténant plusieurs modules, on peut arriver à créer un nouveau programme basé sur ces mêmes modules.
      Mon programme n'est qu'un utilisateur de sous programmes/routines/modules.
      Il est destiné à l'édition ( via un utilitaire d'édition en ncurses ) de nouveaux programmes dont les paramètres ( aide, modules au format json avec messages d'erreur pour chacun d'entre eux etc... ) seront classés au sein d'une base de donnée.
      Chaque sous routine devra dès lors être imbriquée dans une liste doublement chaînée afin de faciliter la correction des erreurs, l'éditeur permettant à tout instant de lancer un programme partiel ( ou pas ) afin d'en vérifier les résultats intermédiaires.
      J'ai même envie de donner à mon module le nom "concat", la fonctionnalité qui m'a amené à rédiger ce topic.

      Alors je sais que c'est un peu imbuvable question longueur,
      

      ```J'essaierai de faire mieux la prochaine fois, en me rappelant du conseil donné plus haut par j_m et en gardant un formatage décent.

          Préférez strncat et strncpy qui vous éviterons des ennuis, d'autant que vous recalculez la longueur juste avant.
      

      J'ai fait comme vous me l'avez préconisé.

      Vous aviez raison pour le calloc… En effet, result peut avoir été alloué au préalable.
      voici le code spécifique à concat dans internal:

                  int len = 0;
          for(int l = 1; l < p->args[i][1] - 1; l++)
              len += strlen(p->commands[i][l]);
          if(*size < len){
              *size = len;
              if(!*size)
                  *result = calloc(len + 1, sizeof(char));
              else
                  *result = realloc(*result, (len + 1) * sizeof(char));
          }
          strncpy(*result, p->commands[i][1], strlen(p->commands[i][1]));
          for(int l = 2; l < p->args[i][1] - 1; l++)
          {
              strncat(*result, p->commands[i][l], strlen(p->commands[i][l]));
          }
          return 256;
      

      En ce qui concerne size, j'avais oublié de lui affecter len. size est un marqueur qui me permet de savoir si result mérite d'être ré-alloué dans fd_readn. Dans ce cas, il est incrémenté en conséquence dans cette dernière fonction avant la prochaine itération de la boucle de process_exec.

      Merci de votre attention.

      Le problème n'est toujours pas résolu.

      • [^] # Re: Reallocation sans free ?

        Posté par  . Évalué à 3.

        Vous aviez raison pour le calloc… En effet, result peut avoir été alloué au préalable.
        voici le code spécifique à concat dans internal:

        Je vois toujours un calloc qui ferait office de malloc dans ce code, tout en négligeant de libérer le pointeur précédent au préalable.

        • calloc avec une taille d’élément à 1, soit la taille d'un char, c'est un malloc.

        Et il existait (existe?) d'autres calloc douteux que celui de cette fonction.

        *size = len;
        if(!*size)
            *result = calloc(len + 1, sizeof(char));

        Dans cette branche, len vaut 0 quoi qu'il arrive non ?
        Donc, c'est équivalent à malloc(1) ?

        • [^] # Re: Reallocation sans free ?

          Posté par  . Évalué à 1.

          Bonjour Mr Marec,
          je vais tenter d'expliquer cette partie du code:
          1. result: résultat en chaîne de caractères des opérations précédentes de l'exécution de la chaîne de modules courante - je nommerai ces dernières "listing". Il est censé être ré-allouer dès que nécessaire et libéré après conservation dans le tableau process_datas->result de ma structure process_datas, ce à la fin de l'exécution de chaque listing.
          2. size: taille du string result nécessaire à la fonction fd_readn pour le calcul d'un espace supplémentaire éventuel - le but étant de limiter les libérations.
          1. len: somme des longueurs des strings à concaténer ( ne peut pas être égal à 0 ):
          - code de la fonction interne concat revisité:

                  int len = 0;
                  for(int l = 1; l < p->args[*i][1] - 1; l++)
                      len += strlen(p->commands[*i][l]);
                  if(*size < len){
                      *size = len;
                      if(!*size)
                          *result = calloc(len + 1, sizeof(char));
                      else
                          *result = realloc(*result, (len + 1) * sizeof(char));
                  }
                  strncpy(*result, p->commands[*i][1], strlen(p->commands[*i][1]));
                  for(int l = 2; l < p->args[*i][1] - 1; l++)
                  {
                      strncat(*result, p->commands[*i][l], strlen(p->commands[*i][l]));
                  }
                  ++(*i);
                  return 256;
          

          remarquez l'incrémentation du i de la boucle de process_exec et dont je vérifie la validité dans cette même dernière fonction ( améliorée ), afin d'éviter de passer par le pipe si jamais le listing courant se terminait par une commande internal:

                  if((ret = process_datas_internal(p, &result, &size, &i)) == EXIT_FAILURE)
                  {
                      free(result);
                      perror("Bad internal process");
                      return EXIT_FAILURE;
                  }else if(i == p->size)
                      break;
          

          Mon programme se comporte mieux ( il fonctionne ). Par contre, je vais devoir m'arracher les cheveux pour trouver le pointeur non libéré que m'indique valgrind:

          ==26878== LEAK SUMMARY:
          ==26878==    definitely lost: 128 bytes in 1 blocks
          

          merci encore une fois de votre attention. Si vous souhaitez collaborer à la conception de ce module destiné à la création de nouveaux modules… n'hésitez pas à m'en faire part.

          • [^] # Re: Reallocation sans free ?

            Posté par  . Évalué à 2.

            je vais tenter d'expliquer cette partie du code:

            Clairement: tout ce que je vous indique est valide, quoi que vous fassiez en amont.

            [SNIP] Il est censé être ré-allouer

            Ré-allouer, c'est appeler realloc, pas calloc. Je le répète: vos appels à calloc n'ont pas de sens:

            1. la taille demandée est toujours 1 ( sizeof (char) ): utilisez malloc.
            2. Vous ne vérifiez jamais que result n'est pas null donc que result se doit d'être libéré avant d'appeler calloc.
            3. Petite astuce realloc fonctionne comme un malloc si le pointeur n'avait pas été alloué en premier lieu. Vous pouvez l'utiliser partout. (mais ça donnera l'impression que vous ne maîtrisez pas vous allocations.)

            Et cela se retrouve dans plusieurs parties de votre code.

            1. len: somme des longueurs des strings à concaténer ( ne peut pas être égal à 0 ):

            C'est vous qui le dite, pas votre code:

            *size = len; /* copie de la valeur de len dans size*/
            if(!*size) /*  si size vaut 0,  donc si len vaut 0 ==> if(len==0) */
                *result = /* et si result devait etre lib'er'e d'abord ? */
                  calloc(len + 1, sizeof(char)); /* malloc (len+1), donc malloc(1) */

            Si en fait, vous vouliez allouer result parce qu'il ne l'était pas ou plus, vérifiez le directement:

            if(NULL==result)

            Enfin:

            valgrind

            En fait, memcheck.
            Pour avoir plus de précision sur l'origine de la fuite, utilisez --leak-check=full et consorts.

          • [^] # Re: Reallocation sans free ?

            Posté par  . Évalué à 3.

            je vais tenter d'expliquer cette partie du code:

            Faites mieux: vérifiez vous même, à l'aide d' assertion.

            Par exemple, avant d'allouer:

            assert(result!=NULL);

            ou avant d'affirmer:

            ne peut pas être égal à 0

            if(!*size){
            assert(len!=0);
            /* … */
            }

            Si vous souhaitez collaborer à la conception de ce module destiné à la création de nouveaux modules

            Dans un premier temps, mettez vos sources à disposition en téléchargement, de préférence avec un système de gestion de version au dessus.

            • [^] # Re: Reallocation sans free ?

              Posté par  . Évalué à 1.

              Merci pour votre patience.
              Le code rectifié est le suivant:

                      if(*size < len){
                          if(!*size)
                              *result = calloc(len + 1, sizeof(char));
                          else
                              *result = realloc(*result, (len + 1) * sizeof(char));
                          *size = len;
                      }
              

              avec size affecté en dernier.

              J'espère que c'est plus clair.

              Le programme est maintenant fonctionnel et sans leak.

              Je vais poster, dès la création de la page, le lien github de ce petit bout de code à destination de ceux qui haïssent le bash.

              • [^] # Re: Reallocation sans free ?

                Posté par  . Évalué à 2.

                Le code rectifié est le suivant:

                qui doit être équivalent à ces seules lignes:

                if(*size < len){
                    *result = realloc(*result, len + 1 );
                    *size=len;
                }

                avec size affecté en dernier.

                Ce qui change tout. Ceci dit, je reste persuadé qu'il vaut mieux encadrer result plutôt que size pour déterminer qui est déjà alloué et qui ne l'est pas encore.


                moins il a de branches, mieux se porte le code.

                • [^] # Re: Reallocation sans free ?

                  Posté par  . Évalué à 1.

                  Bon alors là j'ai dû mal me faire comprendre. size est la taille de result. Si size vaut 0 alors result est égal à null. Mais je veut bien concevoir votre aspect de la réalité:

                  if(*size < len){
                      if(*result == NULL)
                          *result = calloc(len +1,  sizeof(char));
                      else
                          *result = realloc(*result, (len + 1) * sizeof(char));
                      *size = len;
                  }
                  

                  et le calloc reste essentiel !

                  • [^] # Re: Reallocation sans free ?

                    Posté par  . Évalué à 3.

                    Si size vaut 0 alors result est égal à null

                    Peut-être, mais c'est la valeur de result qui est importante, c'est lui la clef - et le résulat- des allocations. Dîtes vous que c'est (ou ça devrait être ) l'inverse:

                    • Si result est NULL alors size vaut 0.

                    et le calloc reste essentiel !

                    Et non !

                    si result est NULL:

                    • calloc(len+1,1) == malloc(len+1)== realloc(*result,len+1)

                    Et, je le répète:

                    • sizeof(char) vaut 1, quoiqu'il arrive. C'est le même la seule taille de type qui soit garantie.
                    • N'utilisez donc pas calloc mais malloc.
                    • ptr=realloc(NULL,size) est équivalent à ptr=malloc(size)

                    Man realloc:

                    If ptr is NULL, the realloc function behaves
                    identically to malloc for the specified size

                    • [^] # Re: Reallocation sans free ?

                      Posté par  . Évalué à 1.

                      Merci, je ne connaissais pas cette fonctionnalité de realloc.
                      Aussitôt dit aussitôt fait.
                      Je suis en train d'éditer un programme exemple assez conséquent histoire de montrer les possibilité du module.
                      Je reviens pour poster le lien github.

          • [^] # Re: Reallocation sans free ?

            Posté par  . Évalué à 2.

            Par contre, je vais devoir m'arracher les cheveux pour trouver le pointeur non libéré que m'indique valgrind:

            Meuh non

            valgrind --track-origins=yes   --leak-check=full --show-reachable=yes   tonProgramme

            est ton ami :) pour plus d'options : valgind --help

            Il ne faut pas décorner les boeufs avant d'avoir semé le vent

  • # Voici ce à quoi m'aura servi ce topic

    Posté par  . Évalué à 2.

    Je vous livre ici le code de mon application.
    Faites en bon usage.
    Merci encore

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.