【问题标题】:Investigate a Valgrind Invalid Read调查 Valgrind 无效读取
【发布时间】:2016-05-26 00:24:42
【问题描述】:

当我用 运行我的project 时,我收到一个错误报告。如果我不使用 Valgrind,那么程序看起来是正常的,但是当 Valgrind 报告它时,我确定有问题。

==21286== Invalid read of size 4
==21286==    at 0x404950: fork_pipeline (util.c:296)
==21286==    by 0x403149: execute_pipeline (main.c:177)
==21286==    by 0x4032D5: run_cmd (main.c:221)
==21286==    by 0x403CC3: command (main.c:622)
==21286==    by 0x402B01: main (main.c:933)
==21286==  Address 0x593be68 is 0 bytes after a block of size 24 alloc'd
==21286==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21286==    by 0x4031DD: run_cmd (main.c:204)
==21286==    by 0x403CC3: command (main.c:622)
==21286==    by 0x402B01: main (main.c:933)

冒犯的main.c:204是一行

`struct pipeline *pipe = malloc(chunks->pipes * sizeof *pipe);` 

但我不明白它有什么问题。如果我检查pipes 的值,那么它似乎是正确的。周边代码为:

int run_cmd(const char *cmd) {

    char buffer[2];
    buffer[0] = '|';
    buffer[1] = '\0';
    struct str_list *chunks = list_split(cmd, buffer);
    struct pipeline *pipe = malloc(chunks->pipes * sizeof *pipe);
    pipe->data = malloc(sizeof(char *));
    int i = 0;
    for (i = 0; i < chunks->pipes; i++) {
        pipe[i].data = malloc(sizeof(char *) * BUFFER_SIZE * chunks[i].size);
        int j = 0;
        pipe[i].size = chunks[i].size;
        for (j = 0; j < chunks[i].size; j++) {
            if (chunks[i].argv[j] == NULL) {
                chunks[i].argv[j] = '\0';
                break;
            }
            pipe[i].data[j] = strdup(chunks[i].argv[j]);
            pipe[i].option[0] = chunks[i].option[i];
        }
        pipe[i].data[j] = '\0';
    }
    int status = execute_pipeline(chunks->pipes, pipe);
    return status;
}

如果我查看调试器,那么这些值看起来没问题。我现在的想法是放入断言,以便我可以找到错误出现的位置。

结构有这个声明。

struct str_list {
    char *name;
    int size;
    int pipes;
    char **argv;
    int option[];

};

第二个结构是

struct pipeline {
    char *name;
    int size;
    char **data;
    int option[];
};

更新/编辑

我根据答案更改了代码。

int run_cmd(const char *cmd) {

    char buffer[2];
    buffer[0] = '|';
    buffer[1] = '\0';
    struct str_list *chunks = list_split(cmd, buffer);
    struct pipeline *pipe = malloc(chunks->pipes * sizeof *pipe);
    int i = 0;
    for (i = 0; i < chunks->pipes; i++) {
        pipe[i].data = malloc(sizeof(char **) * BUFFER_SIZE * chunks[i].size);
        int j = 0;
        pipe[i].size = chunks[i].size;
        for (j = 0; j < chunks[i].size; j++) {
            if (chunks[i].argv[j] == NULL) {
                chunks[i].argv[j] = '\0';
                break;
            }
            pipe[i].data[j] = strdup(chunks[i].argv[j]);
            pipe[i].option[0] = chunks[i].option[i];
        }
        pipe[i].data[j] = '\0';
    }
    int status = execute_pipeline(chunks->pipes, pipe);
    return status;
}

仍然获得无效读取。

==23103== Invalid write of size 4
==23103==    at 0x403278: run_cmd (main.c:216)
==23103==    by 0x403CB3: command (main.c:621)
==23103==    by 0x402B01: main (main.c:932)
==23103==  Address 0x592e228 is 0 bytes after a block of size 24 alloc'd
==23103==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23103==    by 0x4031DD: run_cmd (main.c:204)
==23103==    by 0x403CB3: command (main.c:621)
==23103==    by 0x402B01: main (main.c:932)
==23103== 
==23104== Invalid read of size 4
==23104==    at 0x404940: fork_pipeline (util.c:296)
==23104==    by 0x403149: execute_pipeline (main.c:177)
==23104==    by 0x4032C5: run_cmd (main.c:220)
==23104==    by 0x403CB3: command (main.c:621)
==23104==    by 0x402B01: main (main.c:932)
==23104==  Address 0x592e228 is 0 bytes after a block of size 24 alloc'd
==23104==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23104==    by 0x4031DD: run_cmd (main.c:204)
==23104==    by 0x403CB3: command (main.c:621)
==23104==    by 0x402B01: main (main.c:932)

第 216 行:pipe[i].option[0] = chunks[i].option[i];

第 204 行:struct pipeline *pipe = malloc(chunks-&gt;pipes * sizeof *pipe);

【问题讨论】:

  • 你为什么要在pipe-&gt;data 中使用char * 类型的内存分配值来破坏for 以及for 循环中的malloc 呢?
  • @t0mm13b 如果我不对其进行 malloc,那么我会在 pipe[i].option[0] = chunks[i].option[i]; 收到错误消息。我是 C 的这个详细级别的新手,所以也许你知道?我知道我应该 malloc 动态内存,但结构有 3 个级别,我不知道如何用它的成员 malloc 结构。
  • 请出示struct pipe的声明
  • @t0mm13b 好的。现在你明白了。
  • 没有看到任何与data 成员相关的内容?

标签: valgrind c struct valgrind memory-alignment


【解决方案1】:

查看 valgrind 输出,

似乎分配内存以保存pipe-&gt;data最初,以char *类型反映的数量(在x86平台上,通常是1字节,在其他可能会因编译器和平台定义的实现而异),然后在for 循环中,使用实际字节调用malloc

删除初始呼叫中的malloc

pipe->data = malloc(sizeof(char *));

奖励这将消除潜在的内存泄漏

编辑

所以data 是一个“动态字符串数组”

for 循环中:

pipe[i].data = malloc(sizeof(char *) * BUFFER_SIZE * chunks[i].size);

将其更改为:

pipe[i].data = malloc(sizeof(char **) * BUFFER_SIZE * chunks[i].size);

【讨论】:

  • @Programmer400 编辑了我的答案
  • 数据在哪里,没看到?仅供参考,大小 4 正在触发,一个 int,通常在 32 位平台上,此后它的 4 个字节。请更新代码以反映。
  • sizeof *pipe,一个小测试,在malloc调用之后立即执行printf("sizeof *pipe = %d\n", sizeof *pipe);,运行它看看,告诉我结果。等等,那应该是pipes 不是 pipe 吗?
  • 似乎有些混乱,struct pipeline *pipe vs struct pipeline,看到也有成员pipe....
  • 什么*pipe?您根据struct pipeline *pipe = malloc(chunks-&gt;pipes * sizeof *pipe); 声明了一个变量pipe,并将其引用为sizeof *pipe?那不应该是sizeof *pipeline吗?
【解决方案2】:

正如你所拥有的那样,你在struct str_liststruct pipeline 中为option 的字段使用了一个灵活的数组。

您必须通过分配结构来考虑该空间。我已经编译并运行了你的代码,但是我改变了:

struct pipeline {
    char *name;
    int size;
    char **data;
    int *option; // pointer to int
};

和:

struct str_list {
    char *name;
    int size;
    int pipes;
    char **argv;
    int *option; // pointer to int

};

这样做你需要确保你添加了 malloc 调用这个指针。

struct str_list *chunks = list_split(cmd, buffer);
struct pipeline *pipe = malloc(chunks->pipes * sizeof *pipe);
pipe->data = malloc(sizeof(char *));
int i = 0;
for (i = 0; i < chunks->pipes; i++) {
    pipe[i].data = malloc(sizeof(char *) * BUFFER_SIZE * chunks[i].size);
    int j = 0;
    pipe[i].size = chunks[i].size;
    for (j = 0; j < chunks[i].size; j++) {
        if (chunks[i].argv[j] == NULL) {
            chunks[i].argv[j] = '\0';
            break;
        }
        pipe[i].option = malloc(sizeof(int) * 10); // However many options...
        chunks[i].option = malloc(sizeof(int) * 10); // However many options...
        chunks[i].option[i] = 0;
        pipe[i].data[j] = strdup(chunks[i].argv[j]);
        pipe[i].option[0] = chunks[i].option[i];

我检查了list_split 函数中的util.c 文件,您从未设置过option 字段,因此我明确初始化chunks[i].option[i] = 0

在这些更改之后,那些 valgrind 不再吐出这些错误,但是,您仍然有很多内存泄漏。

【讨论】:

  • 非常感谢。这个答案真的很有帮助。是的,我还有一些内存泄漏,但我们解决了我所询问的问题。
猜你喜欢
  • 1970-01-01
  • 2018-07-07
  • 2017-04-09
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多