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

C++调用execve启动子进程时命令行参数传递不全问题

问题原因

参数丢失的核心错误出在arg_list的构造逻辑上:
原代码中char *arg_list[] = {const_cast <char *>(program_name.data()), *arguments, nullptr};这行存在本质逻辑错误:

  1. *arguments等价于取arguments数组的第一个元素(也就是arg1),arguments数组里存储的arg2、arg3根本没有被放入arg_list数组
  2. 按照POSIX规范,execve的第二个参数是以空指针结尾的字符串指针数组,函数读取参数时会一直向后读指针,直到遇到nullptr才停止。你构造的arg_list里放完第一个参数就直接放了nullptr,自然读不到后续参数。

除此之外原代码还存在几处其他bug:

  • main函数存在多余的闭合花括号,语法无法正常编译
  • EXITFAILURE拼写错误,正确宏为EXIT_FAILURE
  • 未处理execve调用失败的场景(比如目标程序不存在时子进程会直接异常退出)
  • 父进程未调用waitpid回收子进程资源,会产生僵尸进程
  • 对std::string::data()做const_cast存在未定义行为风险
修复后代码

LaunchProcess.cpp

#include <unistd.h>
#include <sys/wait.h>
#include <iostream>
#include <cstdlib>
#include <cerrno>
#include <cstring>

pid_t spawnChild(const char* program, char** arg_list) {
    pid_t ch_pid = fork();
    if(ch_pid < 0){
        std::cerr << "Fork failed: " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    } else if (ch_pid > 0){
        std::cout << "Spawned Child with Process Identification: " << ch_pid << std::endl;
        // 等待子进程退出回收资源
        int status;
        waitpid(ch_pid, &status, 0);
        if (WIFEXITED(status)) {
            std::cout << "child " << ch_pid << " terminated, exit code: " << WEXITSTATUS(status) << std::endl;
        }
        return ch_pid;
    } else {
        execve(program, arg_list, nullptr);
        // execve只有调用失败才会返回,走到这里说明执行出错
        std::cerr << "Execve failed: " << strerror(errno) << std::endl;
        _exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[]){
    if (argc < 2) {
        std::cerr << "Usage: ./launch <program> [args...]" << std::endl;
        return EXIT_FAILURE;
    }
    // arg_list长度:参数个数(argc-1, 去掉argv[0]) + 1个nullptr终止位
    char *arg_list[argc];
    // 第一个参数是目标程序名
    arg_list[0] = argv[1];
    // 拷贝后续所有参数
    for (int i = 2; i < argc; i++) {
        arg_list[i-1] = argv[i];
    }
    // 最后必须加nullptr终止
    arg_list[argc-1] = nullptr;

    spawnChild(argv[1], arg_list);
    return EXIT_SUCCESS;
}

program.cpp(原代码无逻辑问题,无需修改)

#include <stdio.h>

int main(int argc, char *argv[])
{
    for (int i = 0; i < argc; i++)
        printf("Argument %d is %s\n", i, argv[i]);
    return 0;
}
验证结果

编译后执行./launch program arg1 arg2 arg3,将得到预期输出:

Spawned Child with Process Identification: 44331
Argument 0 is program
Argument 1 is arg1
Argument 2 is arg2
Argument 3 is arg3
child 44331 terminated, exit code: 0
关键注意点
  • 传给execve的argv数组必须满足两个要求:第一个元素为可执行程序的名称,最后一个元素必须是空指针nullptr,中间按顺序排列所有传入参数
  • 不要用单独解引用指针数组首元素的方式传递多个参数,数组不会自动展开,必须把每个参数的指针依次放入传给execve的数组中
  • execve调用成功后会直接替换子进程地址空间,只有调用失败时才会有返回值,必须对返回场景做错误处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:18:35