Skip to content

Commit 58cb1b8

Browse files
committed
Fix for python#1415 pythonw.exe fails because std streams a missing
After a long discussion about the problem with Windows GUI apps Guido decided that sys.stdin, stdout and stderr should be None when the C runtime library returns invalid file descriptors for the standard streams. So far the only known cases are Windows GUI apps and scripts started with pythonw on Windows. The OS restrictions are tight enough to catch the problem on other OSes.
1 parent f05149a commit 58cb1b8

4 files changed

Lines changed: 63 additions & 13 deletions

File tree

Doc/library/sys.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,13 @@ always available.
513513
could be useful to restore the actual files to known working file objects in
514514
case they have been overwritten with a broken object.
515515

516+
.. note::
517+
518+
Under some conditions ``stdin``, ``stdout`` and ``stderr`` as well as the
519+
original values ``__stdin__``, ``__stdout__`` and ``__stderr__`` can be
520+
None. It is usually the case for Windows GUI apps that aren't connected to
521+
a console and Python apps started with :program:`pythonw`.
522+
516523

517524
.. data:: tracebacklimit
518525

@@ -571,3 +578,4 @@ always available.
571578
Module :mod:`site`
572579
This describes how to use .pth files to extend ``sys.path``.
573580

581+

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ Core and Builtins
3434
- Added a new option -b to issues warnings (-bb for errors) about certain
3535
operations between bytes/buffer and str like str(b'') and comparsion.
3636

37+
- The standards streams sys.stdin, stdout and stderr may be None when the
38+
when the C runtime library returns an invalid file descriptor for the
39+
streams (fileno(stdin) < 0). For now this happens only for Windows GUI
40+
apps and scripts started with `pythonw.exe`.
41+
3742
Extension Modules
3843
-----------------
3944

Objects/fileobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ PyFile_NewStdPrinter(int fd)
363363
{
364364
PyStdPrinter_Object *self;
365365

366-
if ((fd != fileno(stdout) && fd != fileno(stderr)) || fd < 0) {
366+
if (fd != fileno(stdout) && fd != fileno(stderr)) {
367367
/* not enough infrastructure for PyErr_BadInternalCall() */
368368
return NULL;
369369
}

Python/pythonrun.c

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ initstdio(void)
717717
PyObject *bimod = NULL;
718718
PyObject *m;
719719
PyObject *std = NULL;
720-
int status = 0;
720+
int status = 0, fd;
721721

722722
/* Hack to avoid a nasty recursion issue when Python is invoked
723723
in verbose mode: pre-import the Latin-1 and UTF-8 codecs */
@@ -748,35 +748,72 @@ initstdio(void)
748748
}
749749

750750
/* Set sys.stdin */
751-
if (!(std = PyFile_FromFd(fileno(stdin), "<stdin>", "r", -1,
752-
NULL, "\n", 0))) {
751+
fd = fileno(stdin);
752+
/* Under some conditions stdin, stdout and stderr may not be connected
753+
* and fileno() may point to an invalid file descriptor. For example
754+
* GUI apps don't have valid standard streams by default.
755+
*/
756+
if (fd < 0) {
757+
#ifdef MS_WINDOWS
758+
std = Py_None;
759+
Py_INCREF(std);
760+
#else
753761
goto error;
762+
#endif
754763
}
764+
else {
765+
if (!(std = PyFile_FromFd(fd, "<stdin>", "r", -1, NULL,
766+
"\n", 0))) {
767+
goto error;
768+
}
769+
} /* if (fd < 0) */
755770
PySys_SetObject("__stdin__", std);
756771
PySys_SetObject("stdin", std);
757772
Py_DECREF(std);
758773

759774
/* Set sys.stdout */
760-
if (!(std = PyFile_FromFd(fileno(stdout), "<stdout>", "w", -1,
761-
NULL, "\n", 0))) {
762-
goto error;
763-
}
775+
fd = fileno(stdout);
776+
if (fd < 0) {
777+
#ifdef MS_WINDOWS
778+
std = Py_None;
779+
Py_INCREF(std);
780+
#else
781+
goto error;
782+
#endif
783+
}
784+
else {
785+
if (!(std = PyFile_FromFd(fd, "<stdout>", "w", -1, NULL,
786+
"\n", 0))) {
787+
goto error;
788+
}
789+
} /* if (fd < 0) */
764790
PySys_SetObject("__stdout__", std);
765791
PySys_SetObject("stdout", std);
766792
Py_DECREF(std);
767793

768794
#if 1 /* Disable this if you have trouble debugging bootstrap stuff */
769795
/* Set sys.stderr, replaces the preliminary stderr */
770-
if (!(std = PyFile_FromFd(fileno(stderr), "<stderr>", "w", -1,
771-
NULL, "\n", 0))) {
772-
goto error;
773-
}
796+
fd = fileno(stderr);
797+
if (fd < 0) {
798+
#ifdef MS_WINDOWS
799+
std = Py_None;
800+
Py_INCREF(std);
801+
#else
802+
goto error;
803+
#endif
804+
}
805+
else {
806+
if (!(std = PyFile_FromFd(fd, "<stderr>", "w", -1, NULL,
807+
"\n", 0))) {
808+
goto error;
809+
}
810+
} /* if (fd < 0) */
774811
PySys_SetObject("__stderr__", std);
775812
PySys_SetObject("stderr", std);
776813
Py_DECREF(std);
777814
#endif
778815

779-
if (0) {
816+
if (0) {
780817
error:
781818
status = -1;
782819
}

0 commit comments

Comments
 (0)