You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

malloc后出现Valgrind「Invalid write of size 8」错误原因排查

Shell命令解析函数的Valgrind内存错误分析

我需要解析类Shell命令并将其存储到char**中,用于传递给execv系统调用。以下函数功能符合预期,但用Valgrind运行时出现了内存错误,请问错误原因是什么?

问题代码

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

Valgrind错误信息

==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)

错误原因分析

  • 数组内存越界:第23行仅为retval分配了1个char*的空间,但循环中每次i++后直接写入retval[i],超出了已分配的内存范围,导致Valgrind检测到无效写/读操作。
  • 冗余内存分配导致泄漏:第24、28行的malloc(sizeof(char))完全无用,因为strtok返回的是原字符串内的指针,后续赋值直接覆盖了malloc返回的地址,造成内存泄漏。
  • 参数数组终止逻辑不严谨:execv要求参数数组必须以NULL结尾,当前代码虽然最后会将retval[i]设为NULL,但这是通过越界写入实现的,属于未定义行为,只是侥幸能运行。

修复后的代码

char **input_delimit(char *command) {
    char **retval = NULL;
    const char *space = " ";
    int count = 0;
    char *token = strtok(command, space);

    // 先统计token数量
    while (token != NULL) {
        count++;
        token = strtok(NULL, space);
    }

    // 分配足够空间(包含末尾的NULL)
    retval = malloc(sizeof(char*) * (count + 1));
    if (retval == NULL) {
        return NULL;
    }

    // 重新分割字符串填充数组
    token = strtok(command, space);
    for (int i = 0; i < count; i++) {
        retval[i] = token;
        token = strtok(NULL, space);
    }
    retval[count] = NULL; // 严格添加终止符

    return retval;
}

内容的提问来源于stack exchange,提问作者Giomell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:15:27