C语言读取文件执行Shell脚本时出现无限循环问题排查
问题分析与修复方案
当运行包含3行及以上命令的脚本时,shell陷入无限循环,核心问题出在内存泄漏引发堆损坏,以及未正确处理内置命令exit,具体分析和修复如下:
问题1:内存泄漏导致堆损坏
在myShellScript函数中,args指针每次循环都会被wish_split_line重新赋值,但只有最后一次分配的内存被free,前面所有循环产生的内存都发生泄漏。当泄漏积累到一定程度时,会破坏堆内存结构,导致文件指针fptr或fgets的行为异常,无法正确检测到文件末尾,从而进入无限循环。
修复代码
修改myShellScript的循环逻辑,每次执行完命令后立即释放args:
// When myShell is called with a Script as Argument int myShellScript(char filename[100]) { // printf("Received Script. Opening %s", filename); FILE *fptr; char line[200]; char **args; fptr = fopen(filename, "r"); if (fptr == NULL) { printf("\nUnable to open file."); return 1; } else { // printf("\nFile Opened. Parsing. Parsed commands displayed first."); while(fgets(line, sizeof(line), fptr)!= NULL) { args= wish_split_line(line); wish_execute(args); free(args); // 每次循环后释放args,避免内存泄漏 } } fclose(fptr); // 移除循环外的free(args),内存已在循环内释放 return 1; }
问题2:exit命令未正确终止脚本
如果wish_execute未将exit作为内置命令处理,而是当作外部命令执行,子进程执行exit只会终止自身,父进程会继续循环读取脚本内容。即使脚本到末尾,内存损坏也可能导致循环无法终止。
修复方案
修改wish_execute函数,将exit作为内置命令处理:
- 检测到
args[0]为"exit"时,返回特殊值(如0) - 在
myShellScript中根据返回值跳出循环:
// 修改myShellScript的循环部分 while(fgets(line, sizeof(line), fptr)!= NULL) { args= wish_split_line(line); int exec_ret = wish_execute(args); free(args); if (exec_ret == 0) { // 触发exit命令,终止脚本循环 break; } } // 在wish_execute中添加exit处理逻辑(示例) int wish_execute(char **args) { if (args[0] == NULL) { return 1; } if (strcmp(args[0], "exit") == 0) { return 0; // 返回0告知调用者终止循环 } // 处理其他内置命令... // 执行外部命令 return wish_launch(args); }
额外检查点
- 确认
wish_split_line返回的args数组以NULL结尾,避免execvp执行出错 - 检查
p1.sh等外部脚本是否存在修改父进程脚本文件的操作(如追加内容),这也可能导致脚本被无限读取
内容的提问来源于stack exchange,提问作者Oreofe Solarin
相关产品推荐
相关产品推荐

