多管道进程间输入输出流重定向异常问题
多管道模拟程序进程挂起问题排查与修复
你的管道模拟程序在处理ls -la | wc | wc -c这类多管道命令时出现挂起,核心原因是execvp所需的argv数组未以NULL指针终止,同时命令解析逻辑存在潜在缺陷。
问题根源分析
1. argv数组缺少NULL终止符
execvp函数要求传入的argv数组必须以NULL结尾,否则会读取超出数组边界的内存,引发未定义行为。你的parse_commands函数仅填充了命令参数,未在argv[link->argc]位置设置NULL,这会导致:
- 中间进程(如
wc)可能无法正常退出,使得管道写端始终处于打开状态; - 后续进程(如最后的
wc -c)会一直等待管道输入,最终引发挂起。
2. 命令分割逻辑的硬编码缺陷
create_chain函数中处理管道符|时,硬编码跳过2个字符(tmp = tmp2 = tmp + 2;),假设|前后都有空格。若命令中出现|前后无空格的情况(如ls|wc),会导致命令截取错误,丢失部分字符。
修复方案
修复1:为argv数组添加NULL终止符
修改parse_commands函数,填充完参数后添加NULL终止符,同时优化空格处理:
#include <ctype.h> // 需要包含此头文件处理isspace void parse_commands(char *command, chain_link_t *link) { char *tmp = command; char *tmp2 = command; link->argc = 0; // 从0开始计数更合理 while ((tmp = strchr(tmp, ' '))) { // 跳过连续空格 if (tmp == tmp2) { tmp2 = ++tmp; continue; } link->argv[link->argc] = strndup(tmp2, tmp - tmp2); link->argc++; tmp2 = ++tmp; } if (strlen(tmp2) > 0) { link->argv[link->argc] = strdup(tmp2); link->argc++; } // 必须添加NULL终止符,满足execvp要求 link->argv[link->argc] = NULL; link->command = link->argc > 0 ? link->argv[0] : NULL; }
修复2:完善管道符分割逻辑
修改create_chain函数,灵活处理|前后的空格,避免硬编码偏移:
void create_chain(char *command, chain_t *chain) { char *tmp = command; char *tmp2 = command; chain->chain_links_count = 0; while ((tmp = strchr(tmp, '|'))) { // 跳过命令段开头的空格 while (tmp2 < tmp && isspace((unsigned char)*tmp2)) { tmp2++; } // 跳过命令段结尾的空格 char *end = tmp - 1; while (end >= tmp2 && isspace((unsigned char)*end)) { end--; } // 仅当命令段非空时解析 if (end >= tmp2) { parse_commands(strndup(tmp2, end - tmp2 + 1), &(chain->chain_links[chain->chain_links_count])); chain->chain_links_count++; } // 移动到|后面的第一个非空格字符 tmp++; while (isspace((unsigned char)*tmp)) { tmp++; } tmp2 = tmp; } // 处理最后一段命令 if (strlen(tmp2) > 0) { // 跳过开头空格 while (isspace((unsigned char)*tmp2)) { tmp2++; } if (strlen(tmp2) > 0) { parse_commands(strdup(tmp2), &(chain->chain_links[chain->chain_links_count])); chain->chain_links_count++; } } }
额外优化:修复内存泄漏
当前代码中strndup/strdup分配的内存未释放,长期运行会导致内存泄漏。添加内存释放函数并在主函数中调用:
void free_chain(chain_t *chain) { for (int i = 0; i < chain->chain_links_count; i++) { for (int j = 0; j < chain->chain_links[i].argc; j++) { free(chain->chain_links[i].argv[j]); } } } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <command-chain>\n", argv[0]); return EXIT_FAILURE; } chain_t chain; create_chain(argv[1], &chain); run_chain(&chain); free_chain(&chain); // 释放分配的内存 return 0; }
验证
修复后执行ls -la | wc | wc -c,程序会正常结束,不会出现挂起现象,同时也能正确处理|前后无空格的命令格式。
内容的提问来源于stack exchange,提问作者Tameris Isamidinova
相关产品推荐
相关产品推荐

