简体   繁体   English

malloc 后出现 Valgrind“大小 8 的无效写入”错误

[英]Valgrind "Invalid write of size 8" error after malloc

So I want to parse a shell-like command and store it on a char** in order to pass it as an argument on the execv system call.所以我想解析一个类似 shell 的命令并将它存储在一个 char** 上,以便将它作为参数传递给 execv 系统调用。 In the function below the parsing and storing works correctly.在下面的 function 中,解析和存储工作正常。

char ** input_delimit(char *command){            // 19
    char **retval;                               // 20
    const char space[2]=" ";                     // 21
    int i=0;                                     // 22
    retval=(char**)malloc(sizeof(char*));        // 23
    retval[i]=(char*)malloc(sizeof(char));       // 24
    retval[i]=strtok(command,space);             // 25
    while(retval[i]!=NULL){                      // 26
        i++;                                     // 27
        retval[i]=(char*)malloc(sizeof(char));   // 28
        retval[i]=strtok(NULL,space);            // 29
    }                                            // 30
    return retval;                               // 31
}                                                // 32

When I run my code with Valgrind, I get the following error messages (although it does correctly what I want it to do).当我使用 Valgrind 运行我的代码时,我收到以下错误消息(尽管它正确地执行了我希望它执行的操作)。 Why does this happen?为什么会这样?

==824== Invalid write of size 8
==824==    at 0x109410: input_delimit (shell.c:28)
==824==    by 0x109493: execute_command (shell.c:35)
==824==    by 0x109600: main (shell.c:64)
==824==  Address 0x4a489d8 is 0 bytes after a block of size 8 alloc'd
==824==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==824==    by 0x1093A7: input_delimit (shell.c:23)
==824==    by 0x109493: execute_command (shell.c:35)
==824==    by 0x109600: main (shell.c:64)
==824==
==824== Invalid write of size 8
==824==    at 0x109439: input_delimit (shell.c:29)
==824==    by 0x109493: execute_command (shell.c:35)
==824==    by 0x109600: main (shell.c:64)
==824==  Address 0x4a489d8 is 0 bytes after a block of size 8 alloc'd
==824==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==824==    by 0x1093A7: input_delimit (shell.c:23)
==824==    by 0x109493: execute_command (shell.c:35)
==824==    by 0x109600: main (shell.c:64)
==824==
==824== Invalid read of size 8
==824==    at 0x109450: input_delimit (shell.c:26)
==824==    by 0x109493: execute_command (shell.c:35)
==824==    by 0x109600: main (shell.c:64)
==824==  Address 0x4a489d8 is 0 bytes after a block of size 8 alloc'd
==824==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==824==    by 0x1093A7: input_delimit (shell.c:23)
==824==    by 0x109493: execute_command (shell.c:35)
==824==    by 0x109600: main (shell.c:64)

You dynamically allocated memory only for one pointer您仅为一个指针动态分配了 memory

   retval=(char**)malloc(sizeof(char*));

So this loop所以这个循环

   while(retval[i]!=NULL){
           i++;
           retval[i]=(char*)malloc(sizeof(char));
           retval[i]=strtok(NULL,space);
   }

invokes undefined behavior.调用未定义的行为。

Moreover these statements此外,这些声明

retval[i]=(char*)malloc(sizeof(char));
retval[i]=strtok(command,space)

produce a memory leak because memory was allocated and its address was assigned to the pointer retval[i] and in the next statement the pointer was reassigned.产生 memory 泄漏,因为 memory 已分配,其地址已分配给指针retval[i] ,并且在下一条语句中重新分配了指针。 So the address of the allocated memory is lost.所以分配的memory的地址丢失了。

You need to use realloc for the pointer retval within the while loop.您需要在 while 循环中对指针retval使用realloc

This...这个...

 retval=(char**)malloc(sizeof(char*));

... allocates enough space to store one char * . ...分配足够的空间来存储一个char *

This...这个...

 retval[i]=(char*)malloc(sizeof(char));

... allocates space for one char and assigns a pointer to it to retval[i] . ...为一个char分配空间并将指向它的指针分配给retval[i] That space is subsequently leaked when you overwrite that pointer with a different one:当您用另一个指针覆盖该指针时,该空间随后会泄漏:

 retval[i]=strtok(command,space);

But now comes the main problem.但现在来了主要问题。 retval points to space large enough for one char * . retval指向一个足够大的空间char * Therefore, every iteration of this...因此,这个的一次迭代......

 i++; retval[i]=(char*)malloc(sizeof(char)); retval[i]=strtok(NULL,space);

... overruns the bounds of the allocated space (not to mention allocating and immediately leaking another block). ...超出分配空间的边界(更不用说分配并立即泄漏另一个块)。 I would expect Valgrind to notice, and to emit exactly such a diagnostic as you describe.我希望 Valgrind 能够注意到,并发出与您描述的完全相同的诊断信息。

Suggestions:建议:

  1. Start out by allocating space for at least two blocks, because you will need at least that for any valid command.首先为至少两个块分配空间,因为对于任何有效命令,您至少需要它。

  2. Skip those single- char allocations.跳过那些单char分配。 Not only do they serve no useful purpose, they are actually harmful.它们不仅没有用处,而且实际上是有害的。

  3. When you fill up the allocated space without reaching the end of the command, use realloc() to obtain space for more words.当您在未到达命令末尾的情况下填满分配的空间时,请使用realloc()为更多单词获取空间。 This implies that you must keep track of how much space you have already allocated.这意味着您必须跟踪您已经分配了多少空间。 Example:例子:

     char *temp = realloc(retval, new_capacity * sizeof(*retval)); if (.temp) { // handle allocation failure..; } else { retval = temp; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM