开发Shell时execvp权限拒绝与字符串拼接异常问题
问题根源及修复方案
核心问题1:野指针与栈内存失效
你的代码存在两个直接导致args[1]值突变的内存非法访问问题:
- 空格分支提前释放内存:处理空格分割参数时,你为
temp_arg分配堆内存并赋值给args[j],但紧接着就调用free(temp_arg)。这会让args[j]变成野指针,后续访问该内存时,内容已被系统回收或覆盖。char *temp_arg = malloc(k+1); // ...赋值操作 args[j] = temp_arg; free(temp_arg); // 直接释放了args[j]指向的内存,后续访问非法 - 换行分支栈局部变量失效:处理换行时,你用栈上的局部数组
temp_arg存储参数,再将args[j]指向该数组。但栈局部变量在离开当前if块后就会被销毁,后续执行malloc等操作时,栈内存会被新数据覆盖,导致args[1]指向的内容变成随机值。char temp_arg[k+1]; // 栈上局部数组,出if块后失效 args[j] = temp_arg; // 赋值后后续访问指向已失效的栈内存
核心问题2:路径拼接逻辑错误
你手动循环拼接路径的方式存在隐患:
- 最后一行
path[strlen(path)] = '\0';多余且危险,因为此时path未完全初始化,strlen(path)可能读取到非法内存。正确做法是直接用path[len] = '\0';,因为len已经是/bin/与命令的长度之和。
修复后的代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> #define MAX_CMD_BUFFER 256 void extern_com(char* buffer){ int i = 0, j = 1, k = 0; pid_t pid; char *args[5]; char temp[MAX_CMD_BUFFER]; args[0] = "/bin/"; args[4] = NULL; while(buffer[i] != '\0'){ temp[k] = buffer[i]; if(buffer[i] == '\n'){ temp[k] = '\0'; // 改用堆内存存储参数,避免栈内存失效 char *temp_arg = malloc(strlen(temp) + 1); strcpy(temp_arg, temp); args[j] = temp_arg; break; } if(buffer[i] == ' '){ temp[k] = '\0'; char *temp_arg = malloc(strlen(temp) + 1); strcpy(temp_arg, temp); args[j] = temp_arg; j += 1; k = 0; i += 1; // 不提前释放内存,父进程在wait后统一释放 continue; } k++; i++; } // 初始化剩余参数位为NULL for(; j < 4; j++){ args[j] = NULL; } // 安全拼接路径:用strcpy+strcat简化逻辑 char path[MAX_CMD_BUFFER]; strcpy(path, args[0]); strcat(path, args[1]); printf("path: %s\n", path); pid = fork(); if(pid == 0) { execvp(path, args); perror("exec"); exit(EXIT_FAILURE); // exec失败后确保子进程退出 } else { wait(NULL); // 父进程在子进程结束后释放堆内存 for(int m = 1; m < 4; m++){ if(args[m] != NULL){ free(args[m]); } } } }
额外优化建议
- 用
strtok函数分割命令行参数,比手动循环处理空格和换行更简洁可靠。 - 路径拼接改用
snprintf,避免栈数组溢出风险:snprintf(path, sizeof(path), "%s%s", args[0], args[1]); - 子进程在
execvp失败后必须调用exit,防止子进程继续执行父进程代码。
内容的提问来源于stack exchange,提问作者shinny.dogma
相关产品推荐
相关产品推荐

