0

このコードのデバッグについて助けが必要です。問題が malloc と free にあることはわかっていますが、どこで、なぜ、どのように修正するのか正確にはわかりません。答えないでください:「gdbを使用してください」とそれだけです。私はそれをデバッグするためにgdbを使用しますが、私はまだそれについてあまり知りません.

ありがとう。

#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;
} 
4

4 に答える 4

3

C の文字列は null で終わるため、メモリ内の実際のサイズは length+1 です。

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

あなたが持っている必要があります

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

編集:Aethが言ったように、mallocのすべての出現を変更して、その追加のヌル文字用のスペースを含める必要があります:

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));
于 2010-04-17T14:34:36.057 に答える
2

次のようにメモリを動的に割り当てる場合cmd_info->infile:

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

null終了文字にスペースを割り当てていません。

への割り当ても同様です。cmd_info->outfile

charにスペースを割り当ててnnさの文字列をコピーすると、配列の最後に保持されているメタデータが上書きされると思います。mallocこのバグは、メモリの割り当てを解除するために呼び出したときにfreefree がそのメタデータを見つけられないときに表示されます。

編集:

変化する:

num_elems = i;

num_elems = i+1;

で引数の終わりをマークしているのでNULL

cmd_info->arg[iarg] = NULL;

このためのスペースを割り当てる必要があります。

于 2010-04-17T14:32:20.730 に答える
2
  1. char終端の null を処理するには、文字列ごとに余分なものを割り当てる必要があります。

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

  2. 配列に追加char*を割り当てる必要があります。cmd_info->argこの追加の要素にはNULL、引数の配列の終わりを示す が格納されます。

    cmd_info->arg = (char **) ( malloc((num_elems+1) * sizeof(char *)) );


リストされた両方の変更が行われた後、プログラムがエラーなしですべてのメモリを正常に解放することをシステムで確認しました。

于 2010-04-17T14:37:47.603 に答える
1

一般に、このエラーは通常、何かがmalloc()'d ブロックの外側 (最後または最初の前) にデータを書き込んだ結果です。これにより、メモリ アロケータの内部ブックキーピング構造が破損する可能性があります。

他の人は、あなたのコードの特定の問題をすでに指摘しています。より深く隠されている場合、 Valgrindがデバッグに役立つことがわかりました。コードの速度が著しく低下する代わりに、不正なメモリ アクセス (「無効な読み取り」および「無効な書き込み」の形で) を非常に細かいレベルで検出できます。dmallocなどのメモリ デバッガーも役立ちます。オーバーヘッドはほとんどかかりませんが、私の経験では、すべてを見つけるには Valgrind ほど優れていません。

「memcheck」モードの Valgrind は、メモリ アクセス エラーを、プログラム内のどこで発生したかを示すスタック トレースと共に出力します。通常、「無効なポインター」エラーが発生したfree()場合、memcheck が検出する無効な書き込みが先行します。

于 2010-04-17T14:41:49.867 に答える