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

C语言调用system执行cp命令时目标路径意外重复的问题

故障根因

核心问题是代码直接修改了getenv()返回的内存,导致进程内HOME环境变量被意外篡改,后续shell解析~路径时展开错误。

  • getenv("HOME")返回的指针直接指向进程环境表中存储HOME值的内存区域,这块内存不属于用户可随意写入的自定义缓冲区。代码中strcpy(path,strcat(getenv("HOME"),"/.nanocfgmgr"));直接对getenv()返回的指针调用strcat(),属于C标准未定义行为,在当前运行环境下的实际效果是:原HOME值(如/home/user)被原地拼接了/.nanocfgmgr,全局HOME环境变量被篡改为/home/user/.nanocfgmgr。
  • 调用system()执行命令时,shell会将命令中的~自动展开为当前进程的HOME变量值,代码中拼接的~/.nanocfgmgr/会被展开为/home/user/.nanocfgmgr/.nanocfgmgr/,最终出现路径重复拼接的错误。
  • 手动在终端执行相同命令正常,是因为终端进程的HOME变量未被篡改,路径展开逻辑符合预期。
其他潜在问题
  • snprintf()会自动在生成的字符串末尾添加\0终止符,手动在参数中传入"\0"属于无意义写法,不影响功能但冗余。
  • 代码中path、cfg_path缓冲区固定长度仅50字节,若用户家目录路径较长会触发缓冲区溢出,存在内存破坏风险。
  • 连续使用strcat拼接命令字符串时,不会做边界检查,极易出现缓冲区溢出问题。
  • 执行mkdir时未加-p参数,若目标目录已存在会抛出无意义的错误提示。
修复方案
  1. 禁止直接修改getenv()返回的字符串,先将环境变量值拷贝到自有缓冲区后再做拼接操作,同时扩大缓冲区长度避免溢出:
int main(int argc, char **argv){
    const char *home = getenv("HOME");
    if (home == NULL) {
        fprintf(stderr, "failed to get HOME environment variable\n");
        exit(EXIT_FAILURE);
    }
    // 缓冲区设置为256字节,覆盖绝大多数路径长度场景
    char path[256] = {0};
    snprintf(path, sizeof(path), "%s/.nanocfgmgr", home);    
    
    char cfg_path[256] = {0};    
    snprintf(cfg_path, sizeof(cfg_path), "%s/configs.json", path);

    // 用snprintf拼接mkdir命令,添加-p参数忽略目录已存在的报错
    char mkdir_cmd[256] = {0};
    snprintf(mkdir_cmd, sizeof(mkdir_cmd), "mkdir -p %s > /dev/null 2>&1", path);
    system(mkdir_cmd);

    // 其余原有逻辑保持不变
    struct argp_option options[]={
        {"save",'s',"NAME",0,"Backs up the configuration file Usage: nanocfgmr NAME [DESCRIPTION]"},
         {0}
    };

    struct argp argp={options,parser};
    struct parser_args *input= malloc(sizeof(struct parser_args));
    input->path = path;
    return argp_parse(&argp,argc,argv,0,0,input);
}
  1. 调整cp命令拼接逻辑,去掉冗余的终止符传参,缓冲区预留足够长度,直接使用提前计算好的绝对路径拼接,不依赖shell的~展开逻辑,进一步降低环境变量异常带来的风险:
int parser(int key,char *arg, struct argp_state *state){
    struct parser_args *input = state->input;
    switch(key){
        case 's': ;
            char *cp = malloc(256);
            snprintf(cp, 256, "cp %s/.nanorc %s/%s", getenv("HOME"), input->path, arg);
            printf("arg = [[%s]]\n", arg); 
            printf("cp = [[%s]]\n", cp);
            system(cp);
            free(cp);
            break;
    }
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:42:20