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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:30:43