mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
Fix race condition in create_stdio()
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.
This commit is contained in:
parent
17227a7334
commit
6fb5bae252
3 changed files with 42 additions and 40 deletions
|
@ -1037,6 +1037,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
|
||||||
|
|
|
@ -10,6 +10,12 @@ Release date: tba
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- 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 #21167: NAN operations are now handled correctly when python is
|
- Issue #21167: NAN operations are now handled correctly when python is
|
||||||
compiled with ICC even if -fp-model strict is not specified.
|
compiled with ICC even if -fp-model strict is not specified.
|
||||||
|
|
||||||
|
|
|
@ -1003,6 +1003,21 @@ 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;
|
||||||
|
fd2 = dup(fd);
|
||||||
|
if (fd2 >= 0)
|
||||||
|
close(fd2);
|
||||||
|
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,
|
||||||
|
@ -1018,6 +1033,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
|
||||||
|
@ -1099,20 +1117,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;
|
||||||
dummy_fd = dup(fd);
|
}
|
||||||
if (dummy_fd < 0)
|
return NULL;
|
||||||
return 0;
|
|
||||||
close(dummy_fd);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize sys.stdin, stdout, stderr and builtins.open */
|
/* Initialize sys.stdin, stdout, stderr and builtins.open */
|
||||||
|
@ -1188,30 +1201,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);
|
||||||
|
@ -1219,15 +1220,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. */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue