【问题标题】:Help with malloc and free: Glibc detected: free(): invalid pointer关于 malloc 和 free 的帮助:检测到 Glibc:free(): invalid pointer
【发布时间】:2010-04-17 14:20:06
【问题描述】:

我需要帮助来调试这段代码。我知道问题出在 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;
} 

【问题讨论】:

  • 你在哪里得到错误?
  • 没有说在哪一行...

标签: c memory-management free malloc


【解决方案1】:

由于 C 中的字符串是以 null 结尾的,因此它们在内存中的实际大小是 length+1,所以不是

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

你应该有

cmd_info-&gt;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));

【讨论】:

  • 我已经改变了,但仍然得到同样的错误。我究竟做错了什么?请帮忙。问题已编辑。
  • 看看my answer,看看你做完第二步后是否还有同样的问题。
【解决方案2】:
  1. 您需要为每个字符串分配一个额外的char 来处理终止的空值。

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

  2. 您需要在cmd_info-&gt;arg 数组中分配一个额外的char*。这个额外的元素将存储NULL,它表示参数数组的结束。

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


我已在我的系统上确认,在进行了列出的两项更改后,程序成功地释放了所有内存而没有错误。

【讨论】:

  • +1,是的,这两个更改应该可以修复程序。很好的发现:)
【解决方案3】:

当您为cmd_info-&gt;infile 动态分配内存时:

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

您没有为终止 null 字符分配空间。

cmd_info-&gt;outfile 的分配也是如此

当您为n char 分配空间并将长度为n 的字符串复制到其中时,我认为这会覆盖malloc 在数组末尾维护的元数据,并且当您调用@ 时会出现此错误987654328@ 将内存释放为空闲未找到该元数据。

编辑:

变化:

num_elems = i;

num_elems = i+1;

由于您使用NULL 标记参数的结尾

cmd_info->arg[iarg] = NULL;

你需要为此分配空间。

【讨论】:

    【解决方案4】:

    一般来说,此错误通常是由于在malloc()'d 块之外(结束或开始之前)写入数据的结果。这可能会破坏内存分配器的内部簿记结构。

    其他人已经指出了您代码中的特定问题。在隐藏得更深的情况下,我发现Valgrind 对调试很有用。以显着降低代码速度为代价,它能够以非常细粒度的级别检测非法内存访问(以“无效读取”和“无效写入”的形式)。诸如dmalloc 之类的内存调试器也很有帮助,而且不会产生几乎一样多的开销,但根据我的经验,在查找所有内容方面不如 Valgrind 好。

    Valgrind 在其“memcheck”模式下,将输出内存访问错误以及它们在程序中发生的位置的堆栈跟踪。通常,当我在free() 中出现“无效指针”错误时,memcheck 会在某个时间点上出现无效写入。

    【讨论】:

      猜你喜欢
      • 2011-07-01
      • 2019-07-31
      • 2014-07-04
      • 2020-08-02
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 2013-07-23
      • 2016-12-29
      相关资源
      最近更新 更多