Bug 670 - system() documentation is incomplete (for standard streams)
Summary: system() documentation is incomplete (for standard streams)
Status: REOPENED
Alias: None
Product: glibc
Classification: Unclassified
Component: manual (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Roland McGrath
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-01-15 21:28 UTC by Vincent Lefèvre
Modified: 2009-10-29 17:43 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2005-01-15 21:28:01 UTC
The ISO C99 standard requires that the behavior of the system() function shall
be documented. The manual does not say anything about the standard streams, and
thus is incomplete, IMHO. In particular, a documentation concerning the standard
streams would be important since the behavior is not intuitive, as shown on the
following example.

Consider the following program, called "stdstreams":

#include <stdio.h>
#include <stdlib.h>

static void out (char *s)
{
  int ret;
  ret = printf ("%s\n", s);
  if (ret < 0)
    {
      fprintf (stderr, "printf error %s: %d\n", s, ret);
      exit (EXIT_FAILURE);
    }
  ret = fflush (stdout);
  if (ret)
    {
      fprintf (stderr, "fflush error %s: %d\n", s, ret);
      exit (EXIT_FAILURE);
    }
}

int main (int argc, char **argv)
{
  if (argc == 1)
    {
      out ("OK 2");
    }
  else
    {
      int ret;
      fclose (stdin);
      if (freopen ("file.out", "w", stdout) == NULL)
        {
          fprintf (stderr, "freopen error\n");
          exit (EXIT_FAILURE);
        }
      out ("OK 1");
      ret = system ("stdstreams");
      fprintf (stderr, "system returned %d\n", ret);
    }
  return 0;
}

With this program, I get:

dixsept:~/wd/src> ./stdstreams 1
fflush error OK 2: -1
system returned 256
dixsept:~/wd/src> cat file.out
OK 1
dixsept:~/wd/src>

Basically, what is performed is:
1. stdin is closed with fclose().
2. stdout is redirected to a file "file.out" with freopen().
3. A string is sent to stdout.
4. system() is called: the child sends a string to its standard output stream.
It appeared that this output failed.

The observed behavior is not surprising when one guesses what happened with the
file descriptors: the child's stdout is associated with fd 1, which is no longer
open since the smallest free fd (0) was chosen for stdout by freopen(). But this
is just a guess and the observed behavior could have been something else.

Intuitively, one could have expected that the string output in step 4 be sent to
file.out too.
Comment 1 Andreas Schwab 2005-01-15 21:57:53 UTC
This has nothing to do with system(), you get the same behaviour when calling  
the program directly with stdout closed.  
  
$ ./stdstreams 1>&-  
fflush error OK 2: -1  
  
Comment 2 Vincent Lefèvre 2005-01-15 22:12:46 UTC
I disagree. In your example, you close stdout, so you get the expected behavior.
In my example, stdout is reopened by freopen(). So, this is different.

If, in your example, stdin is closed (as in my example before system() is
called), then there is no problem:

dixsept:~/wd/src> ./stdstreams <&-
OK 2
Comment 3 Vincent Lefèvre 2005-01-15 22:22:45 UTC
Also, in the shell, you can even redirect stdout after closing stdin:

dixsept:~/wd/src> ./stdstreams <&- >blah
dixsept:~/wd/src> cat blah
OK 2

In any case, I think that there is a lack of documentation for system() and this
bug should be reopened.
Comment 4 Vincent Lefèvre 2005-01-18 00:02:37 UTC
A few notes that, I hope, will make things clearer:

* system() is a C function, not a system call. In C, one deals with files, not
file descriptors (well, at least not in a ISO C99 standard way). So, *from this
point of view*, a C implementation that would make the parent's and the child's
stdout files correspond to the same stream would be quite intuitive. My example
shows that the implementation provided by glibc is different. That's why I think
that it should be documented in some way.

* The behavior one can see in my example depends in fact on how freopen was
implemented. Internally, the freopen implementation could have chosen to reuse
the same file descriptor 1 (instead of taking the lowest free file descriptor).
Note that such internals are not documented in the glibc manual (at least under
the concerned functions). In fact, this is completely transparent as long as
only C functions (except system()) are used. But when system() is called, these
internal mechanisms are no longer transparent for the C programmer. So, even
though the "strange" behavior may initially come from the freopen() function,
something should be said about that under the system() function documentation.

* In my example, I did not close explicitly the file descriptor 1. This happened
only because of non-documented internal mechanisms, that should be regarded as
unknown for the C programmer who uses functions on files only (which is the case
in my example). This point of view makes the remarks on what happens with shell
redirections (that are based on file descriptors) off topic.

I'm reopening the bug for the above reasons (and because there haven't been
additional comments from others).
Comment 5 Andreas Schwab 2005-01-18 00:20:52 UTC
system is completely unrelated to the whole thing.  There is nothing at all 
inside system that changes your stream and file descriptor settings. 
Comment 6 Vincent Lefèvre 2005-01-18 01:18:38 UTC
The stream changes in the command executed by system, so there's a problem.
Comment 7 Vincent Lefèvre 2009-10-29 17:43:43 UTC
If not in the system() description, the problem should be addressed at least in
the exec() description. The current spec is currently contradictory (or not
conform to POSIX), and the user can't rely on the POSIX spec until it is fixed.
For the reference:

http://austingroupbugs.net/view.php?id=173