C++调用execve启动子进程时命令行参数传递不全问题
问题原因
参数丢失的核心错误出在arg_list的构造逻辑上:
原代码中char *arg_list[] = {const_cast <char *>(program_name.data()), *arguments, nullptr};这行存在本质逻辑错误:
*arguments等价于取arguments数组的第一个元素(也就是arg1),arguments数组里存储的arg2、arg3根本没有被放入arg_list数组- 按照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
相关产品推荐
相关产品推荐

