stdout重定向到管道时execlp出现异常行为的原因排查
execlp启动ls输出异常的问题分析
问题描述
我尝试将通过execlp启动的程序输出读取到缓冲区,以下是我的代码:
void do_ls_la_buf() { int piped[2]; if(pipe(piped) == -1) { printf("Couldn't initiate pipe\n"); exit(EXIT_FAILURE); } if(fork() == 0) { close(piped[0]); // close read end of child dup2(piped[1], 1); // stdout to pipe dup2(piped[1], 2); // stderr to pipe close(piped[1]); execlp("/usr/bin/ls", "ls", "-la"); } else { char buf[1024] = ""; close(piped[1]); // close write end of parent while(read(piped[0], buf, sizeof(buf))) { printf("Read from pipe %d chars: %s\n", strlen(buf), buf); } } } int main { do_ls_la_buf(); wait(NULL); }
运行后得到如下输出:
Read from pipe 22 chars: ls: cannot access 'H=' Read from pipe 28 chars: : No such file or directory
由于execlp的参数是硬编码的,我对此结果感到困惑,想知道这是怎么回事?
问题原因与修复
核心问题:main函数签名错误
你的main函数定义不符合C语言标准,正确的签名应该是int main(void)或int main(int argc, char *argv[]),而你写的int main {缺少括号和参数列表,这会导致编译器解析错误,破坏程序栈结构,使得execlp调用时的参数被意外覆盖,最终让ls接收到非法参数(比如H=),触发"找不到文件"的错误。
修复步骤
- 修正
main函数的签名:
int main(void) { do_ls_la_buf(); wait(NULL); return 0; // 补充符合标准的返回值 }
- 优化管道读取逻辑(可选但更安全):
当前用strlen(buf)统计读取长度存在风险,若读取内容不含字符串终止符,strlen会越界。应直接使用read的返回值,并手动添加终止符:
else { char buf[1024]; close(piped[1]); ssize_t n; while((n = read(piped[0], buf, sizeof(buf)-1)) > 0) { buf[n] = '\0'; // 确保字符串终止 printf("Read from pipe %zd chars: %s\n", n, buf); } }
修改后程序即可正常执行ls -la并正确读取输出。
内容的提问来源于stack exchange,提问作者BaridunDuskhide
相关产品推荐
相关产品推荐

