bpo-30555: Fix WindowsConsoleIO fails in the presence of fd redirection (GH-1927)

This works by not caching the handle and instead getting the handle from
the file descriptor each time, so that if the actual handle changes by
fd redirection closing/opening the console handle beneath our feet, we
will keep working correctly.
This commit is contained in:
Segev Finer 2021-04-24 01:00:27 +03:00 committed by GitHub
parent 6b59e662fa
commit 5e437fb872
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 144 additions and 125 deletions

View File

@ -161,4 +161,12 @@ PyAPI_FUNC(int) _Py_dup(int fd);
PyAPI_FUNC(int) _Py_get_blocking(int fd); PyAPI_FUNC(int) _Py_get_blocking(int fd);
PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking); PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking);
#endif /* !MS_WINDOWS */ #else /* MS_WINDOWS */
PyAPI_FUNC(void*) _Py_get_osfhandle_noraise(int fd);
PyAPI_FUNC(void*) _Py_get_osfhandle(int fd);
PyAPI_FUNC(int) _Py_open_osfhandle_noraise(void *handle, int flags);
PyAPI_FUNC(int) _Py_open_osfhandle(void *handle, int flags);
#endif /* MS_WINDOWS */

View File

@ -0,0 +1,2 @@
Fix ``WindowsConsoleIO`` errors in the presence of fd redirection. Patch by
Segev Finer.

View File

@ -8,10 +8,10 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__,
"close($self, /)\n" "close($self, /)\n"
"--\n" "--\n"
"\n" "\n"
"Close the handle.\n" "Close the console object.\n"
"\n" "\n"
"A closed handle cannot be used for further I/O operations. close() may be\n" "A closed console object cannot be used for further I/O operations.\n"
"called more than once without error."); "close() may be called more than once without error.");
#define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \ #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \
{"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__}, {"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__},
@ -110,10 +110,7 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_fileno__doc__,
"fileno($self, /)\n" "fileno($self, /)\n"
"--\n" "--\n"
"\n" "\n"
"Return the underlying file descriptor (an integer).\n" "Return the underlying file descriptor (an integer).");
"\n"
"fileno is only set when a file descriptor is used to open\n"
"one of the standard streams.");
#define _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF \ #define _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF \
{"fileno", (PyCFunction)_io__WindowsConsoleIO_fileno, METH_NOARGS, _io__WindowsConsoleIO_fileno__doc__}, {"fileno", (PyCFunction)_io__WindowsConsoleIO_fileno, METH_NOARGS, _io__WindowsConsoleIO_fileno__doc__},
@ -381,4 +378,4 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored))
#ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF
#define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF
#endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */
/*[clinic end generated code: output=a28b3120fa53b256 input=a9049054013a1b77]*/ /*[clinic end generated code: output=48080572ffee22f5 input=a9049054013a1b77]*/

View File

@ -64,10 +64,7 @@ char _PyIO_get_console_type(PyObject *path_or_fd) {
int fd = PyLong_AsLong(path_or_fd); int fd = PyLong_AsLong(path_or_fd);
PyErr_Clear(); PyErr_Clear();
if (fd >= 0) { if (fd >= 0) {
HANDLE handle; HANDLE handle = _Py_get_osfhandle_noraise(fd);
_Py_BEGIN_SUPPRESS_IPH
handle = (HANDLE)_get_osfhandle(fd);
_Py_END_SUPPRESS_IPH
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return '\0'; return '\0';
return _get_console_type(handle); return _get_console_type(handle);
@ -143,12 +140,11 @@ class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type"
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
HANDLE handle;
int fd; int fd;
unsigned int created : 1; unsigned int created : 1;
unsigned int readable : 1; unsigned int readable : 1;
unsigned int writable : 1; unsigned int writable : 1;
unsigned int closehandle : 1; unsigned int closefd : 1;
char finalizing; char finalizing;
unsigned int blksize; unsigned int blksize;
PyObject *weakreflist; PyObject *weakreflist;
@ -164,7 +160,7 @@ _Py_IDENTIFIER(name);
int int
_PyWindowsConsoleIO_closed(PyObject *self) _PyWindowsConsoleIO_closed(PyObject *self)
{ {
return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE; return ((winconsoleio *)self)->fd == -1;
} }
@ -172,16 +168,12 @@ _PyWindowsConsoleIO_closed(PyObject *self)
static int static int
internal_close(winconsoleio *self) internal_close(winconsoleio *self)
{ {
if (self->handle != INVALID_HANDLE_VALUE) { if (self->fd != -1) {
if (self->closehandle) { if (self->closefd) {
if (self->fd >= 0) {
_Py_BEGIN_SUPPRESS_IPH _Py_BEGIN_SUPPRESS_IPH
close(self->fd); close(self->fd);
_Py_END_SUPPRESS_IPH _Py_END_SUPPRESS_IPH
} }
CloseHandle(self->handle);
}
self->handle = INVALID_HANDLE_VALUE;
self->fd = -1; self->fd = -1;
} }
return 0; return 0;
@ -190,15 +182,15 @@ internal_close(winconsoleio *self)
/*[clinic input] /*[clinic input]
_io._WindowsConsoleIO.close _io._WindowsConsoleIO.close
Close the handle. Close the console object.
A closed handle cannot be used for further I/O operations. close() may be A closed console object cannot be used for further I/O operations.
called more than once without error. close() may be called more than once without error.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_io__WindowsConsoleIO_close_impl(winconsoleio *self) _io__WindowsConsoleIO_close_impl(winconsoleio *self)
/*[clinic end generated code: output=27ef95b66c29057b input=185617e349ae4c7b]*/ /*[clinic end generated code: output=27ef95b66c29057b input=68c4e5754f8136c2]*/
{ {
PyObject *res; PyObject *res;
PyObject *exc, *val, *tb; PyObject *exc, *val, *tb;
@ -206,8 +198,8 @@ _io__WindowsConsoleIO_close_impl(winconsoleio *self)
_Py_IDENTIFIER(close); _Py_IDENTIFIER(close);
res = _PyObject_CallMethodIdOneArg((PyObject*)&PyRawIOBase_Type, res = _PyObject_CallMethodIdOneArg((PyObject*)&PyRawIOBase_Type,
&PyId_close, (PyObject*)self); &PyId_close, (PyObject*)self);
if (!self->closehandle) { if (!self->closefd) {
self->handle = INVALID_HANDLE_VALUE; self->fd = -1;
return res; return res;
} }
if (res == NULL) if (res == NULL)
@ -229,12 +221,11 @@ winconsoleio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self = (winconsoleio *) type->tp_alloc(type, 0); self = (winconsoleio *) type->tp_alloc(type, 0);
if (self != NULL) { if (self != NULL) {
self->handle = INVALID_HANDLE_VALUE;
self->fd = -1; self->fd = -1;
self->created = 0; self->created = 0;
self->readable = 0; self->readable = 0;
self->writable = 0; self->writable = 0;
self->closehandle = 0; self->closefd = 0;
self->blksize = 0; self->blksize = 0;
self->weakreflist = NULL; self->weakreflist = NULL;
} }
@ -269,16 +260,17 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
int rwa = 0; int rwa = 0;
int fd = -1; int fd = -1;
int fd_is_own = 0; int fd_is_own = 0;
HANDLE handle = NULL;
assert(PyWindowsConsoleIO_Check(self)); assert(PyWindowsConsoleIO_Check(self));
if (self->handle >= 0) { if (self->fd >= 0) {
if (self->closehandle) { if (self->closefd) {
/* Have to close the existing file first. */ /* Have to close the existing file first. */
if (internal_close(self) < 0) if (internal_close(self) < 0)
return -1; return -1;
} }
else else
self->handle = INVALID_HANDLE_VALUE; self->fd = -1;
} }
fd = _PyLong_AsInt(nameobj); fd = _PyLong_AsInt(nameobj);
@ -341,14 +333,12 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
goto bad_mode; goto bad_mode;
if (fd >= 0) { if (fd >= 0) {
_Py_BEGIN_SUPPRESS_IPH handle = _Py_get_osfhandle_noraise(fd);
self->handle = (HANDLE)_get_osfhandle(fd); self->closefd = 0;
_Py_END_SUPPRESS_IPH
self->closehandle = 0;
} else { } else {
DWORD access = GENERIC_READ; DWORD access = GENERIC_READ;
self->closehandle = 1; self->closefd = 1;
if (!closefd) { if (!closefd) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Cannot use closefd=False with file name"); "Cannot use closefd=False with file name");
@ -363,21 +353,31 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
on the specific access. This is required for modern names on the specific access. This is required for modern names
CONIN$ and CONOUT$, which allow reading/writing state as CONIN$ and CONOUT$, which allow reading/writing state as
well as reading/writing content. */ well as reading/writing content. */
self->handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE, handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (self->handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
self->handle = CreateFileW(name, access, handle = CreateFileW(name, access,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (self->handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE) {
PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, GetLastError(), nameobj); PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, GetLastError(), nameobj);
goto error; goto error;
} }
if (self->writable)
self->fd = _Py_open_osfhandle_noraise(handle, _O_WRONLY | _O_BINARY);
else
self->fd = _Py_open_osfhandle_noraise(handle, _O_RDONLY | _O_BINARY);
if (self->fd < 0) {
CloseHandle(handle);
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
goto error;
}
} }
if (console_type == '\0') if (console_type == '\0')
console_type = _get_console_type(self->handle); console_type = _get_console_type(handle);
if (self->writable && console_type != 'w') { if (self->writable && console_type != 'w') {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
@ -460,25 +460,14 @@ _io._WindowsConsoleIO.fileno
Return the underlying file descriptor (an integer). Return the underlying file descriptor (an integer).
fileno is only set when a file descriptor is used to open
one of the standard streams.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_io__WindowsConsoleIO_fileno_impl(winconsoleio *self) _io__WindowsConsoleIO_fileno_impl(winconsoleio *self)
/*[clinic end generated code: output=006fa74ce3b5cfbf input=079adc330ddaabe6]*/ /*[clinic end generated code: output=006fa74ce3b5cfbf input=845c47ebbc3a2f67]*/
{ {
if (self->fd < 0 && self->handle != INVALID_HANDLE_VALUE) {
_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->fd < 0)
return err_mode("fileno"); return err_closed();
return PyLong_FromLong(self->fd); return PyLong_FromLong(self->fd);
} }
@ -492,7 +481,7 @@ static PyObject *
_io__WindowsConsoleIO_readable_impl(winconsoleio *self) _io__WindowsConsoleIO_readable_impl(winconsoleio *self)
/*[clinic end generated code: output=daf9cef2743becf0 input=6be9defb5302daae]*/ /*[clinic end generated code: output=daf9cef2743becf0 input=6be9defb5302daae]*/
{ {
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return err_closed(); return err_closed();
return PyBool_FromLong((long) self->readable); return PyBool_FromLong((long) self->readable);
} }
@ -507,7 +496,7 @@ static PyObject *
_io__WindowsConsoleIO_writable_impl(winconsoleio *self) _io__WindowsConsoleIO_writable_impl(winconsoleio *self)
/*[clinic end generated code: output=e0a2ad7eae5abf67 input=cefbd8abc24df6a0]*/ /*[clinic end generated code: output=e0a2ad7eae5abf67 input=cefbd8abc24df6a0]*/
{ {
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return err_closed(); return err_closed();
return PyBool_FromLong((long) self->writable); return PyBool_FromLong((long) self->writable);
} }
@ -642,7 +631,7 @@ error:
static Py_ssize_t static Py_ssize_t
readinto(winconsoleio *self, char *buf, Py_ssize_t len) readinto(winconsoleio *self, char *buf, Py_ssize_t len)
{ {
if (self->handle == INVALID_HANDLE_VALUE) { if (self->fd == -1) {
err_closed(); err_closed();
return -1; return -1;
} }
@ -657,6 +646,10 @@ readinto(winconsoleio *self, char *buf, Py_ssize_t len)
return -1; return -1;
} }
HANDLE handle = _Py_get_osfhandle(self->fd);
if (handle == INVALID_HANDLE_VALUE)
return -1;
/* Each character may take up to 4 bytes in the final buffer. /* Each character may take up to 4 bytes in the final buffer.
This is highly conservative, but necessary to avoid This is highly conservative, but necessary to avoid
failure for any given Unicode input (e.g. \U0010ffff). failure for any given Unicode input (e.g. \U0010ffff).
@ -678,7 +671,7 @@ readinto(winconsoleio *self, char *buf, Py_ssize_t len)
return read_len; return read_len;
DWORD n; DWORD n;
wchar_t *wbuf = read_console_w(self->handle, wlen, &n); wchar_t *wbuf = read_console_w(handle, wlen, &n);
if (wbuf == NULL) if (wbuf == NULL)
return -1; return -1;
if (n == 0) { if (n == 0) {
@ -784,10 +777,15 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self)
DWORD bufsize, n, len = 0; DWORD bufsize, n, len = 0;
PyObject *bytes; PyObject *bytes;
DWORD bytes_size, rn; DWORD bytes_size, rn;
HANDLE handle;
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return err_closed(); return err_closed();
handle = _Py_get_osfhandle(self->fd);
if (handle == INVALID_HANDLE_VALUE)
return NULL;
bufsize = BUFSIZ; bufsize = BUFSIZ;
buf = (wchar_t*)PyMem_Malloc((bufsize + 1) * sizeof(wchar_t)); buf = (wchar_t*)PyMem_Malloc((bufsize + 1) * sizeof(wchar_t));
@ -819,7 +817,7 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self)
buf = tmp; buf = tmp;
} }
subbuf = read_console_w(self->handle, bufsize - len, &n); subbuf = read_console_w(handle, bufsize - len, &n);
if (subbuf == NULL) { if (subbuf == NULL) {
PyMem_Free(buf); PyMem_Free(buf);
@ -909,7 +907,7 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size)
PyObject *bytes; PyObject *bytes;
Py_ssize_t bytes_size; Py_ssize_t bytes_size;
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return err_closed(); return err_closed();
if (!self->readable) if (!self->readable)
return err_mode("reading"); return err_mode("reading");
@ -959,12 +957,17 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b)
BOOL res = TRUE; BOOL res = TRUE;
wchar_t *wbuf; wchar_t *wbuf;
DWORD len, wlen, n = 0; DWORD len, wlen, n = 0;
HANDLE handle;
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return err_closed(); return err_closed();
if (!self->writable) if (!self->writable)
return err_mode("writing"); return err_mode("writing");
handle = _Py_get_osfhandle(self->fd);
if (handle == INVALID_HANDLE_VALUE)
return NULL;
if (!b->len) { if (!b->len) {
return PyLong_FromLong(0); return PyLong_FromLong(0);
} }
@ -995,7 +998,7 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b)
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, wbuf, wlen); wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, wbuf, wlen);
if (wlen) { if (wlen) {
res = WriteConsoleW(self->handle, wbuf, wlen, &n, NULL); res = WriteConsoleW(handle, wbuf, wlen, &n, NULL);
if (res && n < wlen) { if (res && n < wlen) {
/* Wrote fewer characters than expected, which means our /* Wrote fewer characters than expected, which means our
* len value may be wrong. So recalculate it from the * len value may be wrong. So recalculate it from the
@ -1027,15 +1030,15 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b)
static PyObject * static PyObject *
winconsoleio_repr(winconsoleio *self) winconsoleio_repr(winconsoleio *self)
{ {
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return PyUnicode_FromFormat("<_io._WindowsConsoleIO [closed]>"); return PyUnicode_FromFormat("<_io._WindowsConsoleIO [closed]>");
if (self->readable) if (self->readable)
return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='rb' closefd=%s>", return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='rb' closefd=%s>",
self->closehandle ? "True" : "False"); self->closefd ? "True" : "False");
if (self->writable) if (self->writable)
return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='wb' closefd=%s>", return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='wb' closefd=%s>",
self->closehandle ? "True" : "False"); self->closefd ? "True" : "False");
PyErr_SetString(PyExc_SystemError, "_WindowsConsoleIO has invalid mode"); PyErr_SetString(PyExc_SystemError, "_WindowsConsoleIO has invalid mode");
return NULL; return NULL;
@ -1051,7 +1054,7 @@ static PyObject *
_io__WindowsConsoleIO_isatty_impl(winconsoleio *self) _io__WindowsConsoleIO_isatty_impl(winconsoleio *self)
/*[clinic end generated code: output=9eac09d287c11bd7 input=9b91591dbe356f86]*/ /*[clinic end generated code: output=9eac09d287c11bd7 input=9b91591dbe356f86]*/
{ {
if (self->handle == INVALID_HANDLE_VALUE) if (self->fd == -1)
return err_closed(); return err_closed();
Py_RETURN_TRUE; Py_RETURN_TRUE;
@ -1077,13 +1080,13 @@ static PyMethodDef winconsoleio_methods[] = {
static PyObject * static PyObject *
get_closed(winconsoleio *self, void *closure) get_closed(winconsoleio *self, void *closure)
{ {
return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); return PyBool_FromLong((long)(self->fd == -1));
} }
static PyObject * static PyObject *
get_closefd(winconsoleio *self, void *closure) get_closefd(winconsoleio *self, void *closure)
{ {
return PyBool_FromLong((long)(self->closehandle)); return PyBool_FromLong((long)(self->closefd));
} }
static PyObject * static PyObject *

View File

@ -1370,13 +1370,10 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
*/ */
if (fileno != -1 && fileno != 0) { if (fileno != -1 && fileno != 0) {
/* Ensure that fileno is within the CRT's valid range */ /* Ensure that fileno is within the CRT's valid range */
_Py_BEGIN_SUPPRESS_IPH fh = _Py_get_osfhandle(fileno);
fh = (HANDLE)_get_osfhandle(fileno); if (fh == INVALID_HANDLE_VALUE)
_Py_END_SUPPRESS_IPH
if (fh==(HANDLE)-1) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
}
/* Win9x appears to need us seeked to zero */ /* Win9x appears to need us seeked to zero */
lseek(fileno, 0, SEEK_SET); lseek(fileno, 0, SEEK_SET);
} }

View File

@ -10098,18 +10098,16 @@ os_pipe_impl(PyObject *module)
attr.bInheritHandle = FALSE; attr.bInheritHandle = FALSE;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
ok = CreatePipe(&read, &write, &attr, 0); ok = CreatePipe(&read, &write, &attr, 0);
if (ok) { if (ok) {
fds[0] = _open_osfhandle((intptr_t)read, _O_RDONLY); fds[0] = _Py_open_osfhandle_noraise(read, _O_RDONLY);
fds[1] = _open_osfhandle((intptr_t)write, _O_WRONLY); fds[1] = _Py_open_osfhandle_noraise(write, _O_WRONLY);
if (fds[0] == -1 || fds[1] == -1) { if (fds[0] == -1 || fds[1] == -1) {
CloseHandle(read); CloseHandle(read);
CloseHandle(write); CloseHandle(write);
ok = 0; ok = 0;
} }
} }
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (!ok) if (!ok)

View File

@ -13,10 +13,10 @@
#include <fcntl.h> #include <fcntl.h>
/* The full definition is in iomodule. We reproduce /* The full definition is in iomodule. We reproduce
enough here to get the handle, which is all we want. */ enough here to get the fd, which is all we want. */
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
HANDLE handle; int fd;
} winconsoleio; } winconsoleio;
@ -67,7 +67,10 @@ _testconsole_write_input_impl(PyObject *module, PyObject *file,
prec->Event.KeyEvent.uChar.UnicodeChar = *p; prec->Event.KeyEvent.uChar.UnicodeChar = *p;
} }
HANDLE hInput = ((winconsoleio*)file)->handle; HANDLE hInput = _Py_get_osfhandle(((winconsoleio*)file)->fd);
if (hInput == INVALID_HANDLE_VALUE)
goto error;
DWORD total = 0; DWORD total = 0;
while (total < size) { while (total < size) {
DWORD wrote; DWORD wrote;

View File

@ -177,19 +177,11 @@ static long
msvcrt_open_osfhandle_impl(PyObject *module, void *handle, int flags) msvcrt_open_osfhandle_impl(PyObject *module, void *handle, int flags)
/*[clinic end generated code: output=b2fb97c4b515e4e6 input=d5db190a307cf4bb]*/ /*[clinic end generated code: output=b2fb97c4b515e4e6 input=d5db190a307cf4bb]*/
{ {
int fd;
if (PySys_Audit("msvcrt.open_osfhandle", "Ki", handle, flags) < 0) { if (PySys_Audit("msvcrt.open_osfhandle", "Ki", handle, flags) < 0) {
return -1; return -1;
} }
_Py_BEGIN_SUPPRESS_IPH return _Py_open_osfhandle(handle, flags);
fd = _open_osfhandle((intptr_t)handle, flags);
_Py_END_SUPPRESS_IPH
if (fd == -1)
PyErr_SetFromErrno(PyExc_OSError);
return fd;
} }
/*[clinic input] /*[clinic input]
@ -207,19 +199,11 @@ static void *
msvcrt_get_osfhandle_impl(PyObject *module, int fd) msvcrt_get_osfhandle_impl(PyObject *module, int fd)
/*[clinic end generated code: output=aca01dfe24637374 input=5fcfde9b17136aa2]*/ /*[clinic end generated code: output=aca01dfe24637374 input=5fcfde9b17136aa2]*/
{ {
intptr_t handle = -1;
if (PySys_Audit("msvcrt.get_osfhandle", "(i)", fd) < 0) { if (PySys_Audit("msvcrt.get_osfhandle", "(i)", fd) < 0) {
return NULL; return NULL;
} }
_Py_BEGIN_SUPPRESS_IPH return _Py_get_osfhandle(fd);
handle = _get_osfhandle(fd);
_Py_END_SUPPRESS_IPH
if (handle == -1)
PyErr_SetFromErrno(PyExc_OSError);
return (HANDLE)handle;
} }
/* Console I/O */ /* Console I/O */

View File

@ -249,10 +249,8 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
if (!Py_LegacyWindowsStdioFlag && sys_stdin == stdin) { if (!Py_LegacyWindowsStdioFlag && sys_stdin == stdin) {
HANDLE hStdIn, hStdErr; HANDLE hStdIn, hStdErr;
_Py_BEGIN_SUPPRESS_IPH hStdIn = _Py_get_osfhandle_noraise(fileno(sys_stdin));
hStdIn = (HANDLE)_get_osfhandle(fileno(sys_stdin)); hStdErr = _Py_get_osfhandle_noraise(fileno(stderr));
hStdErr = (HANDLE)_get_osfhandle(fileno(stderr));
_Py_END_SUPPRESS_IPH
if (_get_console_type(hStdIn) == 'r') { if (_get_console_type(hStdIn) == 'r') {
fflush(sys_stdout); fflush(sys_stdout);

View File

@ -1016,9 +1016,7 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status)
HANDLE h; HANDLE h;
int type; int type;
_Py_BEGIN_SUPPRESS_IPH h = _Py_get_osfhandle_noraise(fd);
h = (HANDLE)_get_osfhandle(fd);
_Py_END_SUPPRESS_IPH
if (h == INVALID_HANDLE_VALUE) { if (h == INVALID_HANDLE_VALUE) {
/* errno is already set by _get_osfhandle, but we also set /* errno is already set by _get_osfhandle, but we also set
@ -1157,9 +1155,7 @@ get_inheritable(int fd, int raise)
HANDLE handle; HANDLE handle;
DWORD flags; DWORD flags;
_Py_BEGIN_SUPPRESS_IPH handle = _Py_get_osfhandle_noraise(fd);
handle = (HANDLE)_get_osfhandle(fd);
_Py_END_SUPPRESS_IPH
if (handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE) {
if (raise) if (raise)
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
@ -1230,9 +1226,7 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works)
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
_Py_BEGIN_SUPPRESS_IPH handle = _Py_get_osfhandle_noraise(fd);
handle = (HANDLE)_get_osfhandle(fd);
_Py_END_SUPPRESS_IPH
if (handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE) {
if (raise) if (raise)
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
@ -2006,13 +2000,9 @@ _Py_dup(int fd)
assert(PyGILState_Check()); assert(PyGILState_Check());
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
_Py_BEGIN_SUPPRESS_IPH handle = _Py_get_osfhandle(fd);
handle = (HANDLE)_get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE)
_Py_END_SUPPRESS_IPH
if (handle == INVALID_HANDLE_VALUE) {
PyErr_SetFromErrno(PyExc_OSError);
return -1; return -1;
}
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH _Py_BEGIN_SUPPRESS_IPH
@ -2122,8 +2112,47 @@ error:
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return -1; return -1;
} }
#endif #else /* MS_WINDOWS */
void*
_Py_get_osfhandle_noraise(int fd)
{
void *handle;
_Py_BEGIN_SUPPRESS_IPH
handle = (void*)_get_osfhandle(fd);
_Py_END_SUPPRESS_IPH
return handle;
}
void*
_Py_get_osfhandle(int fd)
{
void *handle = _Py_get_osfhandle_noraise(fd);
if (handle == INVALID_HANDLE_VALUE)
PyErr_SetFromErrno(PyExc_OSError);
return handle;
}
int
_Py_open_osfhandle_noraise(void *handle, int flags)
{
int fd;
_Py_BEGIN_SUPPRESS_IPH
fd = _open_osfhandle((intptr_t)handle, flags);
_Py_END_SUPPRESS_IPH
return fd;
}
int
_Py_open_osfhandle(void *handle, int flags)
{
int fd = _Py_open_osfhandle_noraise(handle, flags);
if (fd == -1)
PyErr_SetFromErrno(PyExc_OSError);
return fd;
}
#endif /* MS_WINDOWS */
int int
_Py_GetLocaleconvNumeric(struct lconv *lc, _Py_GetLocaleconvNumeric(struct lconv *lc,