Seg fault em free(char **)

Asked

Viewed 76 times

0

I’m developing a shell for my OS discipline. It was going well until some strange mistakes appeared! I can’t give free(args) for I receive seg fault, if I don’t give this free when running multiple commands sometimes find garbage in variable and also get seg fault because the behavior is unexpected!

Below is the main code:

void so_setup() {
    rl_bind_key('\t', rl_complete);
    read_history(HISTORY_FILE);
}

void so_dump(){
    write_history(HISTORY_FILE);
}

/* Loop principal */
void so_loop(){
    char *line,shell_prompt[1000];
    char **args;
    int status;
    shell *s;
    char *token;
    char hostname[100];

    /* Pega o caminho inicial */
    s = (shell*) malloc(sizeof(shell));
    s->caminho = (char*) malloc(sizeof(char)*1024);
    getcwd(s->caminho,1024);

/* Pega o nome da maquina */
gethostname(hostname, sizeof(hostname));

    do{
        /* Encontra o ultimo valor do caminho para prompt */
        token = strrchr(s->caminho,'/');

        /* Imprime o prompt*/
        snprintf(shell_prompt, sizeof(shell_prompt), "%s@%s> ",hostname,token+1);

        /* Recebe a linha */
        line = readline(shell_prompt);

        if (!line)
            break;

        /* Adiciona a linha ao historico */
        add_history(line);

        /* Divide a linha em argumentos */
        args = so_split_line(line);

        /* Executa a linha */
        status = so_execute(s,args);

        free(line);
        /****** ERRO AQUI *****/
    //         free(args);
    }while(status);
}

/* Inicia um ou um grupo de processos */
int so_launch(shell *s,processo *p){
    pid_t pid, wpid;
    int status;
    char comando[1014];
    int fd[2], infile, outfile;
    processo *aux;

    /* Caso eu receba a entrada de outro arquivo usando < */
    if(p->redirectIn){
        infile = p->stdin;
    }
    else
        infile = STDIN_FILENO;

    /* Verifico o grupo de processos */
    for(aux = p; aux; aux = aux->prox){

        /* Se existir um proximo crio um pipe */
        if(aux->prox){
            if(pipe(fd) < 0){
                perror("pipe");
                exit(1);
            }
            outfile = fd[1];
        }
        else{
            /* Caso nao exista um proximo eu verifico se a saida é padrao ou redirecionamento usando > */
            if(aux->redirectOut){
                outfile = aux->stdout;
            }
            else{
                outfile = STDOUT_FILENO;
            }
        }

        /* Dou o fork para criar o processo filho */
        pid = fork();
        if(pid == 0){
            /* Caso estejamos no processo filho setamos os arquivos de entrada e saida */
            if(infile != STDIN_FILENO){
                dup2(infile,STDIN_FILENO);
                close(infile);
            }

            if(outfile != STDOUT_FILENO){
                dup2(outfile,STDOUT_FILENO);
                close(outfile);
            }
            if(aux->args[0][0] == '.' && aux->args[0][1] == '/'){
                sprintf(comando,"%s/%s",s->caminho,aux->args[0]);
                if(execvp(comando, aux->args) == -1){
                    perror("shell");
                }
            }
            else if(execvp(aux->args[0], aux->args) == -1){
                perror("shell");
            }
                exit(1);
        }
        else if( pid < 0){
            perror("shell");
        }
        else{
            /* Caso estejamos no processo pai esperamos pro filho acabar */
            do{
                wpid = waitpid(pid, &status, WUNTRACED);
            } while (!WIFEXITED(status) && !WIFSIGNALED(status));
        }

        if(infile != STDIN_FILENO){
            close(infile);
        }
        if(outfile != STDOUT_FILENO){
            close(outfile);
        }
        infile = fd[0];
    }

    return 1;
}

/* Divide a linha em um vetor de argumentos */
char** so_split_line(char *line){
    int buffsize = TOK_BUFFERSIZE;
    int position = 0;
    char **tokens = (char**) malloc(sizeof(char*) * buffsize);
    char *token;

    if(!tokens){
        fprintf(stderr,"shell: erro de alocacao\n");
        exit(EXIT_FAILURE);
    }

    /* Divide a linha em tokens */
    token = strtok(line,TOK_DELIM);

    while (token){
        tokens[position] = token;

        position++;
        //fprintf(stdout,"********%s\n",tokens[position]);
        /* Caso tenha estourado o tamanho dobra o mesmo */
        if(position >= buffsize){
            buffsize += TOK_BUFFERSIZE;
            tokens = realloc(tokens, sizeof(char*) * buffsize);

            if(!tokens){
                fprintf(stderr,"shell: args = NULL;erro de alocacao");
                exit(EXIT_FAILURE);
            }
        }

        token = strtok(NULL,TOK_DELIM);
    }

    tokens[position] = NULL;
    return tokens;
}

/* Verificando se nao possui nenhum redirecionamento */
void new_filenos(processo *p){
    int i = 0;
    int out = 0;    //         free(args);
    FILE *new_stdout;
    FILE *new_stdin;
    processo *aux;

    /* Caso seja um grupo de processos eu so verifico o ultimo */
    if(p->prox){
        aux = p->prox;
        while(aux->prox) aux = aux->prox;

        while(aux->args[i]){
            if(aux->args[i] && !strcmp(aux->args[i],">")){
                out = 1;
                if(aux->args[i+1]){
                    new_stdout = fopen(aux->args[i+1],"w");
                    aux->stdout = fileno(new_stdout); // pego o numero do descritor do arquivo
                    aux->args[i+1] = NULL;
                    aux->redirectOut = 1; //aviso que esse processo tem redirecionamento pra saida
                }
                else{
                    fprintf(stderr,"Escreva um nome para o arquivo de saida, enviando para o padrao!\n");
                }
                aux->args[i] = NULL;
            }
            i++;
        }
    }
    /* Caso não eu verifico se ele recebe uma entrada ou saida */
    else{
        while(p->args[i]){
             if(!strcmp(p->args[i],"<") && !out){
                 if(p->args[i+1]){
                    new_stdin = fopen(p->args[i+1],"r");
                    p->stdin = fileno(new_stdin);
                    p->args[i+1] = NULL;
                    p->redirectIn = 1; // aviso que esse processo tem redirecionamento pra entrada
                }
                else{
                    fprintf(stderr,"Escreva um nome para o arquivo de entrada, enviando para o padrao!\n");
                }
                p->args[i] = NULL;
                i++;
            }
            if(p->args[i] && !strcmp(p->args[i],">")){
                out = 1;
                if(p->args[i+1]){
                    new_stdout = fopen(p->args[i+1],"w");
                    p->stdout = fileno(new_stdout);
                    p->args[i+1] = NULL;
                    p->redirectOut = 1;
                }
                else{
                    fprintf(stderr,"Escreva um nome para o arquivo de saida, enviando para o padrao!\n");
                }
                p->args[i] = NULL;
            }
            i++;
        }
    }
 }

/* Aloco recursivamente o grupo de processos */
processo* pipes(char **args,int index){

    processo *p;
    int i = index+1;
    int j = 0;
    p = (processo*) malloc(sizeof(p));
    p->args = (char**) malloc(sizeof(char*)*sizeof(args));

    /* Até meu grupo acabar ou eu encontrar um pipe | eu crio um processo com os argumentos */
    while(args[i] && strcmp(args[i],"|")){
        p->args[j] = (char*) malloc(sizeof(char)*(sizeof(args[i])));
        strcpy(p->args[j],args[i]);
        i++;
        j++;
    }
    p->redirectOut = p->redirectIn = 0;
    p->args[i] = NULL;

    /* Caso eu ainda possua um proximo eu crio um outro processo na lista */
    if(args[i+1]){
        p->prox = pipes(args,i);
    }
    else{
        /* Caso seja o ultimo eu finalizo */
        p->prox = NULL;
    }
    return p;
}

/* Função para executar um comando */
int so_execute(shell *s,char **args){
    processo *p;
    if(args[0] == NULL){
        return 1; 
    }

    /* Crio o grupo de processos */
    p = pipes(args,-1);

    /* Verifico redirecionamentos */
    new_filenos(p);

    //     fprintf(stderr,args[0]);

    /* Verifico se não é alguma função builtIn */
    if(!strcmp(args[0],"cd")){
        return so_cd(s,args);
    }
    else if(!strcmp(args[0],"pwd")){
        return so_pwd(s,args);
    }
    else if(!strcmp(args[0],"help")){
        return so_help(args);
    }
    else if(!strcmp(args[0],"exit")){
        return so_exit();
    }
    /* Caso nao seja executo o processo */
    else{
        return so_launch(s,p);
    }
}

I believe the problem lies in so_split_line() but I can’t find him!

Any help thanks!!

Edit:

The error is not in so_split_line(), I tested alone and there was no problem when relocating.

  • I couldn’t see anything wrong with so_split_line. My suggestion is that you run with gdb.

  • @Joséx. By the fact of running with gdb I know that the problem is in free(args)! Thanks for the suggestion

  • So isolate so_split_line and run unit tests on her....

  • @Joséx. Thanks for the tip I hadn’t really thought about it, testing separately there are no problems, I can allocate and dislocate freely! Now I have no floor unfortunately

  • So it’s possible that the function call so_execute(s,args); is corrupting the allocated memory. I think you can see this with gdb.

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.