C++实现shell管道功能时未知命令异常输出问题排查
问题根因
execvp调用失败后,子进程没有主动退出:当执行未知命令las时,execvp返回-1,你仅打印了错误信息,没有终止子进程。此时子进程会继续运行,回到shell的主输入循环,把前序命令ls输出到管道里的内容(也就是当前目录的文件名列表)当成后续要执行的命令解析,因此出现了把README.md、bin等文件名当成命令执行的异常报错。- 仅等待了最后一个子进程:代码末尾的
waitpid(pid, NULL, 0)仅等待最后一个创建的子进程退出,前面所有子进程都没有被回收,会变成僵尸进程,也可能引发资源泄漏相关的异常。 - 父进程的管道文件描述符关闭逻辑存在漏洞:对于
i=0的首个命令,父进程不会关闭对应的管道写端,会导致管道读端永远收不到EOF,前序命令执行完后后序命令可能一直阻塞等待输入。
修复方案
- 子进程
execvp调用失败后,打印错误信息后立刻终止子进程,避免子进程继续执行shell逻辑:
if(execvp(cmds[i][0],cmds[i]) == -1){ cerr << "Unknown command: " << "[" << cmds[i][0] << "]." << endl; exit(EXIT_FAILURE); // 新增这行终止执行失败的子进程 }
- 所有子进程创建完成后,父进程要等待所有子进程退出,而不是仅等最后一个:把末尾的
waitpid(pid, NULL, 0)替换为循环等待逻辑:
// 替换原来的单个waitpid for (int i = 0; i < command_num; i++) { wait(NULL); }
- 修复父进程的管道关闭逻辑,所有管道描述符父进程都要在创建完子进程后全部关闭,避免残留引用:
// 所有子进程创建完成后,父进程统一关闭所有管道文件描述符 for(int j = 0; j < 2*(command_num - 1);j++){ close(fd[j]); }
内容的提问来源于stack exchange,提问作者Benny Chiu
相关产品推荐
相关产品推荐

