2010-04-17 8 views
0

J'ai besoin d'aide pour déboguer ce bout de code. Je sais que le problème est dans malloc et gratuit mais ne peut pas trouver exactement où, pourquoi et comment le réparer. S'il vous plaît ne répondez pas: "Utilisez gdb" et c'est tout. J'utiliserais gdb pour le déboguer, mais je n'en sais toujours pas beaucoup et je l'apprends encore, et j'aimerais avoir, entre-temps, une autre solution.Aide avec malloc et libre: Glibc détectée: free(): pointeur invalide

Merci.

#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/wait.h> 
#include <sys/types.h> 

#define MAX_COMMAND_LENGTH 256 
#define MAX_ARGS_NUMBER  128 
#define MAX_HISTORY_NUMBER 100 

#define PROMPT ">>> " 

int num_elems; 

typedef enum {false, true} bool; 

typedef struct { 
    char **arg;  
    char *infile; 
    char *outfile; 
    int background; 
} Command_Info; 

int parse_cmd(char *cmd_line, Command_Info *cmd_info) 
{ 
    char *arg; 
    char *args[MAX_ARGS_NUMBER];  

    int i = 0; 
    arg = strtok(cmd_line, " "); 
    while (arg != NULL) { 
     args[i] = arg; 
     arg = strtok(NULL, " "); 
     i++; 
    } 

    num_elems = i;precisa em free_mem 
    if (num_elems == 0) 
     return 0; 

    cmd_info->arg = (char **) (malloc(num_elems * sizeof(char *))); 
    cmd_info->infile = NULL; 
    cmd_info->outfile = NULL; 
    cmd_info->background = 0; 

    bool b_infile = false; 
    bool b_outfile = false; 

    int iarg = 0; 
    for (i = 0; i < num_elems; i++) 
    {     
     if (!strcmp(args[i], "<")) 
     {    
      if (b_infile || i == num_elems-1 || !strcmp(args[i+1], "<") || !strcmp(args[i+1], ">") || !strcmp(args[i+1], "&")) 
       return -1;      

      i++; 
      cmd_info->infile = malloc(strlen(args[i]) * sizeof(char)); 
      strcpy(cmd_info->infile, args[i]); 
      b_infile = true; 
     } 

     else if (!strcmp(args[i], ">")) 
     { 
      if (b_outfile || i == num_elems-1 || !strcmp(args[i+1], ">") || !strcmp(args[i+1], "<") || !strcmp(args[i+1], "&")) 
       return -1; 

      i++;  
      cmd_info->outfile = malloc(strlen(args[i]) * sizeof(char)); 
      strcpy(cmd_info->outfile, args[i]); 
      b_outfile = true; 
     } 

     else if (!strcmp(args[i], "&")) 
     { 
      if (i == 0 || i != num_elems-1 || cmd_info->background) 
       return -1; 

      cmd_info->background = true; 
     } 

     else 
     { 
      cmd_info->arg[iarg] = malloc(strlen(args[i]) * sizeof(char)); 
      strcpy(cmd_info->arg[iarg], args[i]); 
      iarg++; 
     } 
    } 

    cmd_info->arg[iarg] = NULL; 

    return 0; 
} 


void print_cmd(Command_Info *cmd_info) 
{ 
    int i; 
    for (i = 0; cmd_info->arg[i] != NULL; i++) 
     printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]); 
    printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);  
    printf("infile=\"%s\"\n", cmd_info->infile); 
    printf("outfile=\"%s\"\n", cmd_info->outfile); 
    printf("background=\"%d\"\n", cmd_info->background); 
} 

void get_cmd(char* str) 
{ 
    fgets(str, MAX_COMMAND_LENGTH, stdin); 
    str[strlen(str)-1] = '\0'; 
} 

pid_t exec_simple(Command_Info *cmd_info) 
{ 
    pid_t pid = fork(); 

    if (pid < 0) 
    { 
     perror("Fork Error"); 
     return -1; 
    } 

    if (pid == 0) 
    { 
     if ((execvp(cmd_info->arg[0], cmd_info->arg)) == -1) 
     { 
      perror(cmd_info->arg[0]); 
      exit(1); 
     } 
    } 

    return pid; 
} 

void type_prompt(void) 
{ 
    printf("%s", PROMPT); 
} 

void syntax_error(void) 
{ 
    printf("msh syntax error\n"); 
} 

void free_mem(Command_Info *cmd_info) 
{ 
    int i; 
    for (i = 0; cmd_info->arg[i] != NULL; i++) 
     free(cmd_info->arg[i]); 
    free(cmd_info->arg); 
    free(cmd_info->infile); 
    free(cmd_info->outfile); 
} 

int main(int argc, char* argv[]) 
{ 
    char cmd_line[MAX_COMMAND_LENGTH]; 
    Command_Info cmd_info; 
    //char* history[MAX_HISTORY_NUMBER]; 

    while (true) 
    { 
     type_prompt(); 

     get_cmd(cmd_line); 

     if (parse_cmd(cmd_line, &cmd_info) == -1) 
     { 
      syntax_error(); 
      continue; 
     } 

     if (!strcmp(cmd_line, "")) 
      continue; 

     if (!strcmp(cmd_info.arg[0], "exit")) 
      exit(0); 

     pid_t pid = exec_simple(&cmd_info); 

     waitpid(pid, NULL, 0); 

     free_mem(&cmd_info); 
    } 

    return 0; 
} 
+0

Où obtenez-vous l'erreur? –

+0

Il ne dit pas à quelle ligne ... – nunos

Répondre

3

Puisque les chaînes en C sont nuls terminaison, leur taille actuall en mémoire est la longueur + 1, donc au lieu de

cmd_info->infile = malloc(strlen(args[i]) * sizeof(char));

Vous devriez avoir

cmd_info->infile = malloc((strlen(args[i])+1) * sizeof(char));

EDIT: Comme l'a dit Aeth, vous besoin de changer chaque occurence de malloc pour contenir l'espace pour ce caractère nul supplémentaire:

cmd_info->arg = (char **) (malloc(num_elems * sizeof(char *))); //this one can stay, since it determines number of strings, not string length 
cmd_info->outfile = malloc((strlen(args[i])+1) * sizeof(char)); 
cmd_info->arg[iarg] = malloc((strlen(args[i])+1) * sizeof(char));
+0

J'ai changé cela, mais toujours la même erreur. Qu'est-ce que je fais mal? S'il vous plaît aider. Question éditée. – nunos

+0

Jetez un coup d'oeil à [ma réponse] (http://stackoverflow.com/questions/2658648/help-with-malloc-and-free-glibc-detected-free-invalid-pointer/2658703#2658703) et voyez si vous ont toujours les mêmes problèmes après avoir fait la deuxième étape. –

+0

Merci beaucoup! Ça a marché! – nunos

2

Lorsque vous allocation dynamique de mémoire pour cmd_info->infile comme:

cmd_info->infile = malloc(strlen(args[i]) * sizeof(char)); 

vous n'êtes pas allouer de l'espace pour la terminaison null car.

même est le cas avec l'allocation pour cmd_info->outfile

Lorsque vous allouez de l'espace pour n omble chevalier et de copier une chaîne de longueur n en elle, je pense que écrasent les métadonnées qui malloc maintient à la fin du tableau et ce bug apparaît lorsque vous appelez free pour libérer la mémoire comme libre ne trouve pas cette méta-données.

EDIT:

Change:

num_elems = i; 

à

num_elems = i+1; 

Puisque vous Marquant la fin des arguments avec NULL

cmd_info->arg[iarg] = NULL; 

vous devez allouer l'espace pour cela.

2
  1. Vous devez allouer un char supplémentaire pour chacune de vos chaînes afin de gérer la valeur nulle finale.

    cmd_info-> arg [iarg] = malloc ((strlen (args [i]) + 1) * sizeof (char));

  2. Vous devez allouer char* supplémentaire dans la baie cmd_info->arg. Cet élément supplémentaire stockera le NULL qui signifie la fin du tableau d'arguments.Cmd_info-> arg = (char **) (malloc ((num_elems + 1) * sizeof (char *)))


J'ai confirmé sur mon système que le programme libère avec succès toute sa mémoire sans erreur après les deux changements énumérés ont été faites.

+0

+1, oui ces deux changements devraient fixer le programme. Bonnes découvertes :) – codaddict

1

En général, cette erreur est généralement le résultat de quelque chose qui écrit des données en dehors d'un bloc malloc() 'd (hors la fin ou avant le début). Cela peut corrompre les structures de comptabilité internes de l'allocateur de mémoire.

D'autres ont déjà signalé le problème particulier dans votre code. Dans les cas où il est plus profondément caché, j'ai trouvé Valgrind pour être utile pour le débogage. Au détriment du ralentissement de code noticable, il est capable de détecter les accès mémoire illégaux (sous forme de "lectures invalides" et "d'écritures invalides") à un niveau très fin. Débogueurs de mémoire tels que dmalloc peuvent également être utiles, et n'imposent pas presque autant de frais généraux, mais dans mon expérience ne sont pas tout à fait aussi bon que Valgrind pour trouver tout. Valgrind, dans son mode 'memcheck', affichera les erreurs d'accès à la mémoire avec une trace de pile de l'endroit où elles se sont produites dans le programme. Habituellement, quand j'ai une erreur "pointeur invalide" dans free(), il sera précédé à un certain point par une écriture invalide que memcheck trouvera.

Questions connexes