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参数,若目标目录已存在会抛出无意义的错误提示。
修复方案
- 禁止直接修改
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); }
- 调整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
相关产品推荐
相关产品推荐

