自定义Shell执行命令后触发Seg Fault且管道功能失效问题求助
自定义Shell问题修复方案
1. 核心段错误问题
问题根因
- exec_cmd函数内存释放逻辑位置错误:你将
cmd_seg链表的释放代码写在了遍历命令段的for循环内部,第一次执行完第一个命令段就会把整个链表全部释放,后续for循环执行cur = cur->next时会访问已释放的野指针,直接触发段错误。 - readLine函数未补字符串结束符:读取输入存入缓冲区后,遇到换行或EOF直接返回,未在缓冲区末尾写入
\0,后续strlen、strtok等字符串操作全部越界访问内存。 - 子进程执行失败未退出:
exec_cmd_seg中execvp执行失败后,子进程没有调用exit退出,会继续运行父进程的逻辑,导致内存重复释放、逻辑混乱。
修复方法
- 将
exec_cmd中释放cmd_seg链表的代码移到for循环外部,等所有命令段执行完成后再释放:
int exec_cmd(struct cmd *command){ int status = 1; struct cmd_seg* cur; struct cmd_seg* pfree; int fd = 0; for(cur = command->root; cur != NULL; cur = cur -> next){ if(cur -> next){ int fd2[2]; pipe(fd2); status = exec_cmd_seg(cur, fd, fd2[1], command->mode, 0); fd = fd2[0]; } else{ status = exec_cmd_seg(cur, fd, 1, command->mode, 0); } } // 释放逻辑移到循环外部 cur = command -> root; pfree = cur; while(cur != NULL){ cur = cur -> next; free(pfree); pfree = cur; } free(command); return status; }
- 修改
readLine函数,返回缓冲区前补结束符:
if(ch == EOF || ch == '\n'){ buffer[pos] = '\0'; // 新增结束符写入 printf("Command: %s\n", buffer); return buffer; }
exec_cmd_seg中execvp失败后加退出逻辑:
int result = execvp(segment->args[0], segment->args); if(result < 0){ printf("\nError Executing Command: %s", segment->args[0]); exit(EXIT_FAILURE); // 新增子进程退出逻辑 }
2. 管道功能异常问题
问题根因
- 文件描述符关闭逻辑错误:
exec_cmd_seg中关闭文件描述符用了else if判断,当in_fd和out_fd都不是标准输入输出时(管道场景),out_fd不会被关闭,管道读端收不到EOF,会一直卡住。 - 单命令段等待逻辑不适用管道:
exec_cmd_seg中每启动一个子进程就立刻waitpid,如果前一个命令的输出超过管道缓冲区,会因为没有读端读取导致写阻塞,整个管道卡死。 - 内置命令返回值判断逻辑冗余:
exec_cmd_seg中判断IsBuiltin == 0才返回,但builtins函数只会返回1或者-1,该判断永远不触发,逻辑混乱。
修复方法
- 修改
exec_cmd_seg的文件描述符关闭逻辑,去掉else if改为独立判断:
if(in_fd != 0){ close(in_fd); } if(out_fd != 1){ // 去掉else,改为独立判断 close(out_fd); }
- 调整管道场景的等待逻辑:所有管道段的子进程全部fork启动完成后,再统一调用
waitpid回收所有子进程,不要启动一个等一个。 - 修正内置命令判断逻辑:
int IsBuiltin = builtins(segment); if(IsBuiltin == 1){ return 1; } // 后续为外部命令执行逻辑
内容的提问来源于stack exchange,提问作者Sigma_Alpha
相关产品推荐
相关产品推荐

