Bug 248281 - popen() inadvertently closes the child's stdout if the parent's fd 1 is another popen'd stream
popen() inadvertently closes the child's stdout if the parent's fd 1 is anoth...
Status: CLOSED UPSTREAM
Product: Fedora
Classification: Fedora
Component: glibc (Show other bugs)
6
All Linux
low Severity low
: ---
: ---
Assigned To: Jakub Jelinek
Fedora Extras Quality Assurance
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2007-07-15 01:33 EDT by r6144
Modified: 2007-11-30 17:12 EST (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2007-07-20 03:53:31 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:


Attachments (Terms of Use)

  None (edit)
Description r6144 2007-07-15 01:33:37 EDT
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.)
Comment 1 Jakub Jelinek 2007-07-20 03:53:31 EDT
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.

Note You need to log in before you can comment on or make changes to this bug.