This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Plea for clarification on bz #12724


Hi,

Bugzilla entry #12724 proposes a (by now committed) change
to fclose(3) behavior based on the following citation from
POSIX.1-2008:

"If the file is not already at EOF, and the file is one capable
of seeking, the file offset of the underlying open file
description shall be adjusted so that the next operation
on the open file description deals with the byte after the
last one read from or written to the stream being closed."

There seems to be an ambiguous corner case, in which case
the behavior adopted is not necessarily wrong, but seems
to be not thought over carefully (see below on the coverage
of the test programs).

The text speaks of "_the_ last one [byte] read from or written to
the stream". That's a definite article, thus it presupposes existence.
So, as I interpret, no definitive statement is here about the case
when there was no read or write done on the stream during its lifetime.

- Is my interpretation correct?
- If not, what rationale is there to make a choice?
- If yes, what practical arguments are there for chosen behavior?

To give some background why I'm asking it:

- Solaris, the OS which is quoted in the bug report as a system
  which is compliant in this regard, chooses the other behavior
  and does not position the file descriptor on close if no I/O
  was done on the stream. This can be demonstrated by the following
  modified version of the test program of the bug report, which
  does not do I/O on the stream (but repositions a duplicate fd).
  The program asserts that the duplicate fd will be positioned back
  to the stream's fd's position upon fclose().

  With glibc >= 2.14, the program completes peacefully, but on Solaris
  the assertion is violated (the original test program, and the one
  included in the related commit [libio/bug-fclose1.c of
  glibc-2.13-161-gfcabc0f]  do complete on both platforms, as they are
  not covering this case).

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#define NAME "test-fclose.t"

int
main (void)
{
  const char buf[] = "hello world";
  int fd;
  int fd2;
  FILE *f;

  /* Prepare a seekable file.  */
  fd = open (NAME, O_RDWR | O_CREAT | O_TRUNC, 0600);
  assert (0 <= fd);
  assert (write (fd, buf, sizeof buf) == sizeof buf);
  assert (lseek (fd, 1, SEEK_SET) == 1);

  /* Create an output stream visiting the file; when it is closed, all
     other file descriptors visiting the file must see the new file
     position.  */
  fd2 = dup (fd);
  assert (0 <= fd2);
  f = fdopen (fd2, "w");
  assert (f);
  assert(lseek(fd, 4, SEEK_SET) == 4);
  assert (fclose (f) == 0);
  errno = 0;
  assert (lseek (fd2, 0, SEEK_CUR) == -1);
  assert (errno == EBADF);
  assert (lseek (fd, 0, SEEK_CUR) == 1);

  /* Likewise for an input stream.  */
  fd2 = dup (fd);
  assert (0 <= fd2);
  f = fdopen (fd2, "r");
  assert (f);
  assert(lseek(fd, 4, SEEK_SET) == 4);
  assert (fclose (f) == 0);
  errno = 0;
  assert (lseek (fd2, 0, SEEK_CUR) == -1);
  assert (errno == EBADF);
  assert (lseek (fd, 0, SEEK_CUR) == 1);

  /* Clean up.  */
  assert (remove (NAME) == 0);

  return 0;
}

- Ruby 1.8.7 build fails with glibc >= 2.14 due to the
  chosen no-I/O-fclose behavior, see

  http://redmine.ruby-lang.org/issues/5108

  They keep around a duplicated file object
  to ensure that the original stdio (which might be
  redirected during the program run) can be restored.
  Even if that part of the code is not used, at GC time
  the duplicate is destroyed, implying an fclose() and
  an unexpected repositioning of stdout.

  By no means I want to defend this rather hacky practice,
  which can be regarded as historical cruft, however, it's
  a case which demonstrates the choice in this regard
  can break things.

Regards,
Csaba


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]