Fedora Account System
Red Hat Associate
Red Hat Customer
Description of problem: The program below gives the error message "sh: line 0: echo: write error: Bad file descriptor". #include <assert.h> #include <stdio.h> int main(void) { FILE *p1, *p2; int result1, result2; fclose(stdout); p1 = popen("echo a", "r"); assert(p1 != NULL); p2 = popen("echo b", "r"); assert(p2 != NULL); result1 = pclose(p1); result2 = pclose(p2); fprintf(stderr, "result1 = %d, result2 = %d\n", result1, result2); return 0; } I dug into this problem with "strace -f", and found that the stdout fd (fd 1) of the child process p2 (pid 5072) got closed before the execve(). pipe([1, 4]) = 0 clone(Process 5071 attached child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f55708) = 5071 [pid 5070] close(4) = 0 [pid 5070] pipe([4, 5]) = 0 [pid 5070] clone(Process 5072 attached child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f55708) = 5072 [pid 5070] close(5) = 0 [pid 5070] close(1) = 0 [pid 5070] waitpid(5071, Process 5070 suspended <unfinished ...> [pid 5071] close(1 <unfinished ...> [pid 5072] close(4 <unfinished ...> [pid 5071] <... close resumed> ) = 0 [pid 5072] <... close resumed> ) = 0 [pid 5071] dup2(4, 1 <unfinished ...> [pid 5072] dup2(5, 1 <unfinished ...> [pid 5071] <... dup2 resumed> ) = 1 [pid 5072] <... dup2 resumed> ) = 1 [pid 5071] close(4 <unfinished ...> [pid 5072] close(5 <unfinished ...> [pid 5071] <... close resumed> ) = 0 [pid 5072] <... close resumed> ) = 0 [pid 5071] execve("/bin/sh", ["sh", "-c", "echo a"], [/* 51 vars */] <unfinished ...> [pid 5072] close(1 <unfinished ...> [pid 5071] <... execve resumed> ) = 0 [pid 5072] <... close resumed> ) = 0 [pid 5072] execve("/bin/sh", ["sh", "-c", "echo b"], [/* 51 vars */] <unfinished ...> This seems to be caused by the following code in libc/libio/iopopen.c: _IO_close (parent_end); if (child_end != child_std_end) { _IO_dup2 (child_end, child_std_end); _IO_close (child_end); } /* POSIX.2: "popen() shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process." */ for (p = proc_file_chain; p; p = p->next) _IO_close (_IO_fileno ((_IO_FILE *) p)); In our case, when doing the second popen(), the first popen()'s fd is 1 and it has just been overwritten by the dup2() call, so it is wrong to close it. Version-Release number of selected component (if applicable): glibc-2.5-10.fc6 How reproducible: Always Steps to Reproduce: 1. Compile the program above and run it. Actual results: sh: line 0: echo: write error: Bad file descriptor result1 = 0, result2 = 256 (result1 might also be 13 (SIGPIPE) if the parent pclose()'d before the child writes its output.) Expected results: result1 = 0, result2 = 0 (Either or both results might also be 13.)
Fixed upstream, will eventually make it into F7 updates and if there will be still FC6 glibc updates, there as well. glibc has been updated in both F7 and FC6 very recently, so it won't be updated again in the very near future.