Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 874dbe8

Browse files
committed
Merge 3.4 (create_stdio)
2 parents d529ebb + 6fb5bae commit 874dbe8

3 files changed

Lines changed: 44 additions & 42 deletions

File tree

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ Jan Palus
10661066
Yongzhi Pan
10671067
Martin Panter
10681068
Mathias Panzenböck
1069+
Marco Paolini
10691070
M. Papillon
10701071
Peter Parente
10711072
Alexandre Parenteau

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ Core and Builtins
1414
Library
1515
-------
1616

17+
- Issue #24891: Fix a race condition at Python startup if the file descriptor
18+
of stdin (0), stdout (1) or stderr (2) is closed while Python is creating
19+
sys.stdin, sys.stdout and sys.stderr objects. These attributes are now set
20+
to None if the creation of the object failed, instead of raising an OSError
21+
exception. Initial patch written by Marco Paolini.
22+
1723
- Issue #24992: Fix error handling and a race condition (related to garbage
1824
collection) in collections.OrderedDict constructor.
1925

Python/pylifecycle.c

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/* Python interpreter top-level routines, including init/exit */
32

43
#include "Python.h"
@@ -963,6 +962,23 @@ initsite(void)
963962
}
964963
}
965964

965+
/* Check if a file descriptor is valid or not.
966+
Return 0 if the file descriptor is invalid, return non-zero otherwise. */
967+
static int
968+
is_valid_fd(int fd)
969+
{
970+
int fd2;
971+
if (fd < 0 || !_PyVerify_fd(fd))
972+
return 0;
973+
_Py_BEGIN_SUPPRESS_IPH
974+
fd2 = dup(fd);
975+
if (fd2 >= 0)
976+
close(fd2);
977+
_Py_END_SUPPRESS_IPH
978+
return fd2 >= 0;
979+
}
980+
981+
/* returns Py_None if the fd is not valid */
966982
static PyObject*
967983
create_stdio(PyObject* io,
968984
int fd, int write_mode, char* name,
@@ -978,6 +994,9 @@ create_stdio(PyObject* io,
978994
_Py_IDENTIFIER(TextIOWrapper);
979995
_Py_IDENTIFIER(mode);
980996

997+
if (!is_valid_fd(fd))
998+
Py_RETURN_NONE;
999+
9811000
/* stdin is always opened in buffered mode, first because it shouldn't
9821001
make a difference in common use cases, second because TextIOWrapper
9831002
depends on the presence of a read1() method which only exists on
@@ -1059,21 +1078,15 @@ create_stdio(PyObject* io,
10591078
Py_XDECREF(stream);
10601079
Py_XDECREF(text);
10611080
Py_XDECREF(raw);
1062-
return NULL;
1063-
}
10641081

1065-
static int
1066-
is_valid_fd(int fd)
1067-
{
1068-
int dummy_fd;
1069-
if (fd < 0 || !_PyVerify_fd(fd))
1070-
return 0;
1071-
_Py_BEGIN_SUPPRESS_IPH
1072-
dummy_fd = dup(fd);
1073-
if (dummy_fd >= 0)
1074-
close(dummy_fd);
1075-
_Py_END_SUPPRESS_IPH
1076-
return dummy_fd >= 0;
1082+
if (PyErr_ExceptionMatches(PyExc_OSError) && !is_valid_fd(fd)) {
1083+
/* Issue #24891: the file descriptor was closed after the first
1084+
is_valid_fd() check was called. Ignore the OSError and set the
1085+
stream to None. */
1086+
PyErr_Clear();
1087+
Py_RETURN_NONE;
1088+
}
1089+
return NULL;
10771090
}
10781091

10791092
/* Initialize sys.stdin, stdout, stderr and builtins.open */
@@ -1158,46 +1171,28 @@ initstdio(void)
11581171
* and fileno() may point to an invalid file descriptor. For example
11591172
* GUI apps don't have valid standard streams by default.
11601173
*/
1161-
if (!is_valid_fd(fd)) {
1162-
std = Py_None;
1163-
Py_INCREF(std);
1164-
}
1165-
else {
1166-
std = create_stdio(iomod, fd, 0, "<stdin>", encoding, errors);
1167-
if (std == NULL)
1168-
goto error;
1169-
} /* if (fd < 0) */
1174+
std = create_stdio(iomod, fd, 0, "<stdin>", encoding, errors);
1175+
if (std == NULL)
1176+
goto error;
11701177
PySys_SetObject("__stdin__", std);
11711178
_PySys_SetObjectId(&PyId_stdin, std);
11721179
Py_DECREF(std);
11731180

11741181
/* Set sys.stdout */
11751182
fd = fileno(stdout);
1176-
if (!is_valid_fd(fd)) {
1177-
std = Py_None;
1178-
Py_INCREF(std);
1179-
}
1180-
else {
1181-
std = create_stdio(iomod, fd, 1, "<stdout>", encoding, errors);
1182-
if (std == NULL)
1183-
goto error;
1184-
} /* if (fd < 0) */
1183+
std = create_stdio(iomod, fd, 1, "<stdout>", encoding, errors);
1184+
if (std == NULL)
1185+
goto error;
11851186
PySys_SetObject("__stdout__", std);
11861187
_PySys_SetObjectId(&PyId_stdout, std);
11871188
Py_DECREF(std);
11881189

11891190
#if 1 /* Disable this if you have trouble debugging bootstrap stuff */
11901191
/* Set sys.stderr, replaces the preliminary stderr */
11911192
fd = fileno(stderr);
1192-
if (!is_valid_fd(fd)) {
1193-
std = Py_None;
1194-
Py_INCREF(std);
1195-
}
1196-
else {
1197-
std = create_stdio(iomod, fd, 1, "<stderr>", encoding, "backslashreplace");
1198-
if (std == NULL)
1199-
goto error;
1200-
} /* if (fd < 0) */
1193+
std = create_stdio(iomod, fd, 1, "<stderr>", encoding, "backslashreplace");
1194+
if (std == NULL)
1195+
goto error;
12011196

12021197
/* Same as hack above, pre-import stderr's codec to avoid recursion
12031198
when import.c tries to write to stderr in verbose mode. */

0 commit comments

Comments
 (0)