[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: mingw lseek bug

From: Eric Blake
Subject: Re: mingw lseek bug
Date: Thu, 24 May 2007 19:35:50 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20070221 Thunderbird/ Mnenhy/

Hash: SHA1

According to Bruno Haible on 5/24/2007 6:12 PM:
> Hi Eric,
> I still don't see a proof that lseek is incorrect on mingw.

I tested by writing test-lseek.c first, and using

echo hi | test-lseek && echo failed

then repeating that test with the benefit of the lseek module, and seeing
the difference in output on mingw.  If test-lseek succeeds when stdin is a
pipe, then it is an indication of a bug in lseek.

>> +# define lseek(f,o,w) \
>> +    (GL_LINK_WARNING ("lseek does not fail with ESPIPE on non-seekable " \
>> +                      "files on some systems - " \
>> +                      "use gnulib module lseek for portability"), \
> You expect that lseek fails on all non-seekable files?

I agree that my wording is over-broad, but do you have any better wording?
 Maybe s/non-seekable files/pipes/.

>    "The behavior of lseek() on devices which are incapable of seeking
>     is implementation-defined."

We just defined it - we use the OS's definition if it was good enough, and
if not, we correct it by saying all non-regular files (pipes, fifos,
sockets, and then some) fail with ESPIPE.

> But have you verified with fstat() that stdin is really a pipe, FIFO, or
> socket?

It could be larger than that set, but yes, the lseek module will correctly
handle pipes, FIFOs, and sockets, and the only other POSIX types with
defined behavior that we must worry about are regular files and directories.

>> +  AC_CACHE_CHECK([whether lseek detects pipes], [gl_cv_func_lseek_pipe],
>> +    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <unistd.h>],
>> +[#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
>> +  Choke me.
>> +#endif])],
>> +      [gl_cv_func_lseek_pipe=yes], [gl_cv_func_lseek_pipe=no])])
> It should be possible to write a real test.

How? Mingw doesn't provide pipe(), socket() is a bear to get right in a
configure test, and I don't know how to coerce autoconf into guaranteeing
that conftest's stdin is either a file or a pipe.

>> * tests/test-lseek.c: New file.
> It would be better if it would also test errno.

OK, I'll see about updating it to do that.

> You said that you got an fflush failure on mingw. Could you please
> show a test program that failed before?

The m4 test suite detected failures on mingw due to this code that got
invoked prior to the syscmd macro, in an attempt to follow the POSIX rule
that for seekable streams, child processes should see the stream at the
next character left unprocessed by the parent:

  if (lseek (STDIN_FILENO, 0, SEEK_CUR) >= 0
      && fflush (stdin) == 0)
      fseeko (stdin, 0, SEEK_CUR);

The failures in the m4 testsuite were due to lost data since the fflush
discarded what was on the pipe, even though the fflush should never have
been reached.

> Adding such a test program to
> the testsuite for 'fflush' would IMO have been the first thing to do.
> Then, with the test case, we can hopefully determine whether the problem
> is mingw's lseek or in gnulib's fflush.

fflush on input pipes is intentionally undefined by POSIX, so I don't know
how to add it to the testsuite.  The gnulib implementation wants to be a
no-op on pipes (ie. the first thing rpl_fflush looks for is whether stdin
is even seekable, via ftello, before doing anything else to input
streams); but on mingw, because the ftello lied, gnulib went on to call
fflush, and the mingw fflush implementation discards unread data on the
pipe.  The bug, then, is not so much that the use of fflush lost data, but
that the use of lseek was followed by fflush.

Note that now, even without guarding the call to gnulib's fflush with
lseek, that gnulib's fflush(input-pipe) is now a no-op on mingw as was the
goal of the gnulib fflush implementation, since the ftello now catches
that fact.  But that does not necessarily hold for all implementations of
fflush that comply to POSIX, so a portable program must still ensure it
does not call fflush on a non-seekable input stream if it wants
predictable behavior.

> I claim that there is also and still a bug in gnulib's fflush: POSIX
> guarantees an ESPIPE failure only for pipes, FIFOs and sockets. But there
> are other types of devices (COM:, NUL: etc.), on which lseek's behaviour
> is unspecified. And you got evidence that when lseek behaves in unexpected
> ways, gnulib's fflush will lose data.

This is not a bug in gnulib, so much as an area of undefined behavior - it
is up to the user to not call fflush (gnulib's or otherwise) if they know
that the file is not in output mode and is not seekable.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org


reply via email to

[Prev in Thread] Current Thread [Next in Thread]