Kaydet (Commit) 874dbe89 authored tarafından Victor Stinner's avatar Victor Stinner

Merge 3.4 (create_stdio)

...@@ -1066,6 +1066,7 @@ Jan Palus ...@@ -1066,6 +1066,7 @@ Jan Palus
Yongzhi Pan Yongzhi Pan
Martin Panter Martin Panter
Mathias Panzenböck Mathias Panzenböck
Marco Paolini
M. Papillon M. Papillon
Peter Parente Peter Parente
Alexandre Parenteau Alexandre Parenteau
......
...@@ -14,6 +14,12 @@ Core and Builtins ...@@ -14,6 +14,12 @@ Core and Builtins
Library Library
------- -------
- Issue #24891: Fix a race condition at Python startup if the file descriptor
of stdin (0), stdout (1) or stderr (2) is closed while Python is creating
sys.stdin, sys.stdout and sys.stderr objects. These attributes are now set
to None if the creation of the object failed, instead of raising an OSError
exception. Initial patch written by Marco Paolini.
- Issue #24992: Fix error handling and a race condition (related to garbage - Issue #24992: Fix error handling and a race condition (related to garbage
collection) in collections.OrderedDict constructor. collection) in collections.OrderedDict constructor.
......
/* Python interpreter top-level routines, including init/exit */ /* Python interpreter top-level routines, including init/exit */
#include "Python.h" #include "Python.h"
...@@ -963,6 +962,23 @@ initsite(void) ...@@ -963,6 +962,23 @@ initsite(void)
} }
} }
/* Check if a file descriptor is valid or not.
Return 0 if the file descriptor is invalid, return non-zero otherwise. */
static int
is_valid_fd(int fd)
{
int fd2;
if (fd < 0 || !_PyVerify_fd(fd))
return 0;
_Py_BEGIN_SUPPRESS_IPH
fd2 = dup(fd);
if (fd2 >= 0)
close(fd2);
_Py_END_SUPPRESS_IPH
return fd2 >= 0;
}
/* returns Py_None if the fd is not valid */
static PyObject* static PyObject*
create_stdio(PyObject* io, create_stdio(PyObject* io,
int fd, int write_mode, char* name, int fd, int write_mode, char* name,
...@@ -978,6 +994,9 @@ create_stdio(PyObject* io, ...@@ -978,6 +994,9 @@ create_stdio(PyObject* io,
_Py_IDENTIFIER(TextIOWrapper); _Py_IDENTIFIER(TextIOWrapper);
_Py_IDENTIFIER(mode); _Py_IDENTIFIER(mode);
if (!is_valid_fd(fd))
Py_RETURN_NONE;
/* stdin is always opened in buffered mode, first because it shouldn't /* stdin is always opened in buffered mode, first because it shouldn't
make a difference in common use cases, second because TextIOWrapper make a difference in common use cases, second because TextIOWrapper
depends on the presence of a read1() method which only exists on depends on the presence of a read1() method which only exists on
...@@ -1059,21 +1078,15 @@ error: ...@@ -1059,21 +1078,15 @@ error:
Py_XDECREF(stream); Py_XDECREF(stream);
Py_XDECREF(text); Py_XDECREF(text);
Py_XDECREF(raw); Py_XDECREF(raw);
return NULL;
}
static int if (PyErr_ExceptionMatches(PyExc_OSError) && !is_valid_fd(fd)) {
is_valid_fd(int fd) /* Issue #24891: the file descriptor was closed after the first
{ is_valid_fd() check was called. Ignore the OSError and set the
int dummy_fd; stream to None. */
if (fd < 0 || !_PyVerify_fd(fd)) PyErr_Clear();
return 0; Py_RETURN_NONE;
_Py_BEGIN_SUPPRESS_IPH }
dummy_fd = dup(fd); return NULL;
if (dummy_fd >= 0)
close(dummy_fd);
_Py_END_SUPPRESS_IPH
return dummy_fd >= 0;
} }
/* Initialize sys.stdin, stdout, stderr and builtins.open */ /* Initialize sys.stdin, stdout, stderr and builtins.open */
...@@ -1158,30 +1171,18 @@ initstdio(void) ...@@ -1158,30 +1171,18 @@ initstdio(void)
* and fileno() may point to an invalid file descriptor. For example * and fileno() may point to an invalid file descriptor. For example
* GUI apps don't have valid standard streams by default. * GUI apps don't have valid standard streams by default.
*/ */
if (!is_valid_fd(fd)) {
std = Py_None;
Py_INCREF(std);
}
else {
std = create_stdio(iomod, fd, 0, "<stdin>", encoding, errors); std = create_stdio(iomod, fd, 0, "<stdin>", encoding, errors);
if (std == NULL) if (std == NULL)
goto error; goto error;
} /* if (fd < 0) */
PySys_SetObject("__stdin__", std); PySys_SetObject("__stdin__", std);
_PySys_SetObjectId(&PyId_stdin, std); _PySys_SetObjectId(&PyId_stdin, std);
Py_DECREF(std); Py_DECREF(std);
/* Set sys.stdout */ /* Set sys.stdout */
fd = fileno(stdout); fd = fileno(stdout);
if (!is_valid_fd(fd)) {
std = Py_None;
Py_INCREF(std);
}
else {
std = create_stdio(iomod, fd, 1, "<stdout>", encoding, errors); std = create_stdio(iomod, fd, 1, "<stdout>", encoding, errors);
if (std == NULL) if (std == NULL)
goto error; goto error;
} /* if (fd < 0) */
PySys_SetObject("__stdout__", std); PySys_SetObject("__stdout__", std);
_PySys_SetObjectId(&PyId_stdout, std); _PySys_SetObjectId(&PyId_stdout, std);
Py_DECREF(std); Py_DECREF(std);
...@@ -1189,15 +1190,9 @@ initstdio(void) ...@@ -1189,15 +1190,9 @@ initstdio(void)
#if 1 /* Disable this if you have trouble debugging bootstrap stuff */ #if 1 /* Disable this if you have trouble debugging bootstrap stuff */
/* Set sys.stderr, replaces the preliminary stderr */ /* Set sys.stderr, replaces the preliminary stderr */
fd = fileno(stderr); fd = fileno(stderr);
if (!is_valid_fd(fd)) {
std = Py_None;
Py_INCREF(std);
}
else {
std = create_stdio(iomod, fd, 1, "<stderr>", encoding, "backslashreplace"); std = create_stdio(iomod, fd, 1, "<stderr>", encoding, "backslashreplace");
if (std == NULL) if (std == NULL)
goto error; goto error;
} /* if (fd < 0) */
/* Same as hack above, pre-import stderr's codec to avoid recursion /* Same as hack above, pre-import stderr's codec to avoid recursion
when import.c tries to write to stderr in verbose mode. */ when import.c tries to write to stderr in verbose mode. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment