[issue1633941] for line in sys.stdin: doesn't notice EOF the first time

Ralph Corderoy report at bugs.python.org
Sat Jan 28 19:31:19 CET 2012


Ralph Corderoy <ralph-pythonbugs at inputplus.co.uk> added the comment:

This most certainly is a bug under Unix and an annoying one.  "Since the
issue is with platform's stdio library" is wrong;  stdio is being used
incorrectly.  It would be nice to see it fixed in the 2.x line.

I've two test programs.

    $ head -42 stdin2.6 stdin3.1
    ==> stdin2.6 <==
    #! /usr/bin/python2.6

    import sys

    for l in sys.stdin:
        print repr(l)
    print 'end'

    ==> stdin3.1 <==
    #! /usr/bin/python3.1

    import sys

    for l in sys.stdin:
        print(repr(l))
    print('end')

    $

For both of them I will type "1 Enter 2 Enter 3 Enter Ctrl-D" without
the spaces, Ctrl-D being my tty's EOF, stty -a.

    $ ./stdin2.6
    1
    2
    3
    '1\n'
    '2\n'
    '3\n'

On the EOF the first iteration of sys.stdin returns and then so do the
others with the buffered lines.  The loop doesn't terminate, a second
Ctrl-D is required, giving.

    end
    $

Next,

    $ ./stdin3.1
    1
    '1\n'
    2
    '2\n'
    3
    '3\n'
    end
    $

perfect output.  Only one Ctrl-D required and better still each line is
returned as it's entered.

ltrace shows python2.6 uses fread(3).  I'm assuming it treats only a
zero return as EOF whereas whenever the return value is less than the
number of requested elements, EOF could have been reached;  feof(3) must
be called afterwards to decide.  Really, ferror(3) should also be called
to see if, as well as returning some elements, an error was detected.

It's this lack of feof() that means the second fread() is required to
trigger the flawed `only 0 return is EOF' logic.

Here's some C that shows stdio works fine if feof() and ferror() are
combined with fread().

    #include <stdio.h>

    int main(void)
    {
        unsigned char s[8192], *p;
        size_t n;

        while ((n = fread(s, 1, 8192, stdin))) {
            printf("%zd", n);
            p = s;
            while (n--)
                printf(" %02hhx", *p++);
            putchar('\n');

            if (feof(stdin)) {
                puts("end");
                break;
            }
            if (ferror(stdin)) {
                fputs("error", stderr);
                return 1;
            }
        }

        return 0;
    }

----------
nosy: +ralph.corderoy

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue1633941>
_______________________________________


More information about the Python-bugs-list mailing list