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

类Shell程序中&&||组合命令场景的内存泄漏修复求助

Shell程序invalid_command && command1 || command2场景下的内存泄漏修复

问题场景

仅在invalid_command && command1 || command2场景下出现内存泄漏:当invalid_command执行失败时,会跳过command1执行command2,此时存在未释放的内存块,Valgrind检测到的泄漏字节数与invalid_command的长度相关(比如输入a && b || echo 3泄漏8字节,aa && b || echo 3泄漏9字节)。

相关函数代码

void execute_user_command(char *command, runData *data, int saved_stderr, const char *error_file) {
    char *copy = strdup(command);
    char *args[MAX_ARGS + 1];  // Array to store command arguments
    int arg_count;
    int background = 0;
    char *sep;
    int status = 0;
    char *check_quotes = NULL;


    // Check for || operator
    sep = strstr(copy, "||");
    char *or_command = NULL;
    if (sep) {
        *sep = '\0';
        sep += 2;
        check_quotes = strdup(copy);
        status = 2;
        while (*sep == ' ') sep++;  // Skip spaces
        or_command = sep;
    }

    // Check for && operator
    sep = strstr(copy, "&&");
    if (sep) {
        *sep = '\0';
        sep += 2;
        check_quotes = strdup(copy);
        while (*sep == ' ') sep++;  // Skip spaces

        split_command(copy, args, &arg_count);
        // If the first command is a special command, handle it
        if (handle_special_commands(copy, data) != -1) {
            // If the second command is also a special command, handle it
            if (handle_special_commands(sep, data) == -1) {
                // If the second command is not a special command, execute it
                execute_user_command(sep, data, saved_stderr, error_file);
            }
        } else {
            // If the first command is not a special command, execute it
            if (execute_command(args, copy, background, error_file, data)) {
                check_matching_quotes(check_quotes, data);
                // If the second command is a special command, handle it
                if (handle_special_commands(sep, data) == -1) {
                    // If the second command is not a special command, execute it
                    execute_user_command(sep, data, saved_stderr, error_file);
                }
                // If the first command wasn't special and resulted in an error, don't execute the second command and skip to the third
            } else if (or_command) {
                if (handle_special_commands(or_command, data) == -1) {
                    execute_user_command(or_command, data, saved_stderr, error_file);
                }

            }
        }
        free(check_quotes);
        free(copy);

        return;
    }

    // Split the command into arguments
    split_command(copy, args, &arg_count);

    if (arg_count == 0) {
        free(copy);
        return;  // Ignore empty commands
    }

    if (arg_count > MAX_ARGS) {  // Command plus 4 arguments is allowed
        fprintf(stderr,"ERR: Too many arguments\n");
        free(copy);
        return;  // Skip commands with more than 4 arguments
    }


    if (arg_count > 0) {
        if (status == 1 || status == 0) {
            execute_command(args, command, background, error_file, data);
        } else {
            if (!execute_command(args, copy, background, error_file, data) &&
                handle_special_commands(or_command, data) == -1) {
                execute_user_command(or_command, data, saved_stderr, error_file);
            } else {
                check_matching_quotes(check_quotes, data);
            }
        }
    }

    free(check_quotes);
    free(copy);
}

Valgrind检测结果

测试输入与对应泄漏情况:

  • 输入:a && b || echo 3

    definitely lost: 8 bytes in 1 blocks

  • 输入:aa && b || echo 3

    definitely lost: 9 bytes in 1 blocks

  • 输入:aa && bb || echo 3

    definitely lost: 10 bytes in 1 blocks

  • 输入:aa && bb || echo 33

    definitely lost: 10 bytes in 1 blocks

Valgrind调用栈:

==8988== (A Number Depends on input as shown above) bytes in 1 blocks are definitely lost in loss record 1 of 1
==8988==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==8988==    by 0x491558E: strdup (strdup.c:42)
==8988==    by 0x10AEE9: execute_user_command (in /home/student/CLionProjects/ShellLike)
==8988==    by 0x10A0A7: process_input (in /home/student/CLionProjects/ShellLike/main)
==8988==    by 0x10B512: main (in /home/student/CLionProjects/ShellLike1/main)

问题排查

泄漏的内存来自strdup调用,核心原因:

  1. 函数开头检查||运算符时,会通过strdup(copy)给check_quotes分配内存;
  2. 接着检查&&运算符时,直接执行check_quotes = strdup(copy)覆盖了之前的指针,导致第一次strdup的内存块丢失,没有被释放;
  3. 当invalid_command执行失败进入else if (or_command)分支时,后续只释放了第二次strdup的check_quotes,第一次分配的内存彻底无法追踪,造成泄漏。

修复方案

在&&检测分支中,给check_quotes重新分配内存前,先检查它是否已经被||检测分配过,如果是则先释放旧内存:

修改&&检测部分的代码:

// Check for && operator
sep = strstr(copy, "&&");
if (sep) {
    *sep = '\0';
    sep += 2;
    // 修复:先释放之前||检测分配的check_quotes内存
    if (check_quotes != NULL) {
        free(check_quotes);
    }
    check_quotes = strdup(copy);
    while (*sep == ' ') sep++;  // Skip spaces

    // 后续代码保持不变...
}

该修复直接解决了指针覆盖导致的内存泄漏问题,无需调整其他逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:36:07