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 */
966982static PyObject *
967983create_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