使用execv()系统调用出现栈溢出崩溃问题求助
问题根源:栈数组越界触发栈溢出
你的程序崩溃完全是因为栈上的bin数组长度不足,strcat操作越界写入破坏了栈结构,直接触发了系统的栈溢出保护机制(Stack Smashing Protector)。
咱们拆解一下问题细节:
- 你定义的
char bin[10] = "/bin/";,这个数组总长度只有10字节。"/bin/"本身就占了6字节(5个可见字符+1个字符串终止符\0),留给后续拼接命令名的空间只剩4字节。 - 一旦
cmd[0]是长度超过4的命令名(比如"python3"是6字节,加上终止符共7字节),strcat(bin, cmd[0])就会往bin数组的边界外写数据,覆盖栈上的关键信息(比如栈帧返回地址、栈保护校验值),最终触发栈溢出报错。
修复方案
这里提供两种可靠的解决方式,优先推荐第一种动态分配内存的方案,更灵活安全:
方式1:动态分配适配命令长度的内存
通过malloc根据命令名的实际长度计算所需空间,彻底避免固定长度的限制:
#include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #include <stdio.h> void execute(char *args[], char *cmd[]) { pid_t pid; int status; // 计算总所需长度:"/bin/"的长度 + 命令名长度 + 1(终止符) size_t bin_total_len = strlen("/bin/") + strlen(cmd[0]) + 1; char *bin = malloc(bin_total_len); if (bin == NULL) { perror("malloc failed"); return; } pid = fork(); // 子进程逻辑 if(pid == 0) { strcpy(bin, "/bin/"); strcat(bin, cmd[0]); execv(bin, args); // 能走到这里说明execv执行失败 perror("execv failed"); free(bin); // 虽然后马上退出,但保持良好习惯 exit(EXIT_FAILURE); } else if (pid == -1) { // 别忘了处理fork失败的情况 perror("fork failed"); free(bin); return; } else { // 等待子进程结束 while(wait(&status) != pid); free(bin); // 父进程必须释放动态分配的内存 } }
方式2:使用系统定义的最大路径长度数组
如果你能确定所有要执行的命令都不会超出系统路径长度限制,可以直接用PATH_MAX定义足够大的数组:
#include <limits.h> // 必须包含这个头文件才能使用PATH_MAX #include <sys/wait.h> #include <unistd.h> #include <stdio.h> #include <string.h> void execute(char *args[], char *cmd[]) { pid_t pid; int status; char bin[PATH_MAX] = "/bin/"; // PATH_MAX通常为4096,足够容纳绝大多数路径 pid = fork(); // 子进程逻辑 if(pid == 0) { strcat(bin, cmd[0]); execv(bin, args); perror("execv failed"); exit(EXIT_FAILURE); } else if (pid == -1) { perror("fork failed"); return; } else { while(wait(&status) != pid); } }
额外代码问题提醒
原代码里还有个容易忽略的小错误:else分支里的perror("error");会在fork成功时也打印错误信息,这是不对的——只有当pid == -1时才说明fork失败,应该把错误打印逻辑放到这个分支里。
另外,execv执行成功是不会返回的,只有执行失败才会走到后续代码,所以子进程里在execv之后一定要加上错误处理和退出逻辑,避免子进程继续执行父进程的代码。
内容的提问来源于stack exchange,提问作者John Novosel
相关产品推荐
相关产品推荐

