[New-bugs-announce] [issue34187] Issues with lazy fd support in _WindowsConsoleIO fileno() and close()

Eryk Sun report at bugs.python.org
Sun Jul 22 05:05:49 EDT 2018


New submission from Eryk Sun <eryksun at gmail.com>:

The _WindowsConsoleIO implementation of fileno should raise a ValueError if the internal handle value is INVALID_HANDLE_VALUE. Currently it raises io.UnsupportedOperation, and only if closefd=True. 

    >>> f = open('conin$', 'r')
    >>> f.close()
    >>> f.fileno()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    io.UnsupportedOperation: Console buffer does not support fileno

    >>> f = open(0, 'r', closefd=False)
    >>> f.close()
    >>> f.fileno()
    0

Also, if lazily opening an fd fails when opening by name (con, conin$, conout$), it should also close the file handle to maintain a consistent state. 

This can be fixed as follows: error out immediately and call err_closed instead of err_mode; and close the handle if _open_osfhandle fails (i.e. fd == -1) and closehandle is set:

    static PyObject *
    _io__WindowsConsoleIO_fileno_impl(winconsoleio *self)
    {
        if (self->handle == INVALID_HANDLE_VALUE) {
            return err_closed();
        }
        
        if (self->fd < 0) {
            _Py_BEGIN_SUPPRESS_IPH
            if (self->writable) {
                self->fd = _open_osfhandle((intptr_t)self->handle,
                                _O_WRONLY | _O_BINARY);
            } else {
                self->fd = _open_osfhandle((intptr_t)self->handle,
                                _O_RDONLY | _O_BINARY);
            }
            _Py_END_SUPPRESS_IPH
        }

        if (self->fd < 0) {
            if (self->closehandle) {
                CloseHandle(self->handle);
            }
            self->handle = INVALID_HANDLE_VALUE;
            return err_closed();
        }

        return PyLong_FromLong(self->fd);
    }

On a related note, there's a bug in internal_close that could potentially be a race condition that closes a handle to an unrelated object. If an fd has been opened, the CRT takes control of the handle. Calling close() will also close the underlying handle. In this case CloseHandle should not be called. This just needs a minor fix to add an `else` clause:

    static int
    internal_close(winconsoleio *self)
    {
        if (self->handle != INVALID_HANDLE_VALUE) {
            if (self->closehandle) {
                if (self->fd >= 0) {
                    _Py_BEGIN_SUPPRESS_IPH
                    close(self->fd);
                    _Py_END_SUPPRESS_IPH
                } else {
                    CloseHandle(self->handle);
                }
            }
            self->handle = INVALID_HANDLE_VALUE;
            self->fd = -1;
        }
        return 0;
    }

----------
components: IO, Windows
keywords: easy (C)
messages: 322138
nosy: eryksun, paul.moore, steve.dower, tim.golden, zach.ware
priority: normal
severity: normal
stage: needs patch
status: open
title: Issues with lazy fd support in _WindowsConsoleIO fileno() and close()
type: behavior
versions: Python 3.6, Python 3.7, Python 3.8

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue34187>
_______________________________________


More information about the New-bugs-announce mailing list