diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 6f1aaff87bb..94e4eb936ec 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -513,6 +513,13 @@ always available. could be useful to restore the actual files to known working file objects in case they have been overwritten with a broken object. + .. note:: + + Under some conditions ``stdin``, ``stdout`` and ``stderr`` as well as the + original values ``__stdin__``, ``__stdout__`` and ``__stderr__`` can be + None. It is usually the case for Windows GUI apps that aren't connected to + a console and Python apps started with :program:`pythonw`. + .. data:: tracebacklimit @@ -571,3 +578,4 @@ always available. Module :mod:`site` This describes how to use .pth files to extend ``sys.path``. + diff --git a/Misc/NEWS b/Misc/NEWS index c79b53109ed..f68ac904ae2 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,11 @@ Core and Builtins - Added a new option -b to issues warnings (-bb for errors) about certain operations between bytes/buffer and str like str(b'') and comparsion. +- The standards streams sys.stdin, stdout and stderr may be None when the + when the C runtime library returns an invalid file descriptor for the + streams (fileno(stdin) < 0). For now this happens only for Windows GUI + apps and scripts started with `pythonw.exe`. + Extension Modules ----------------- diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 6d6022eedfd..5d69911ff66 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -363,7 +363,7 @@ PyFile_NewStdPrinter(int fd) { PyStdPrinter_Object *self; - if ((fd != fileno(stdout) && fd != fileno(stderr)) || fd < 0) { + if (fd != fileno(stdout) && fd != fileno(stderr)) { /* not enough infrastructure for PyErr_BadInternalCall() */ return NULL; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 0b3935ab697..82f8e373caf 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -717,7 +717,7 @@ initstdio(void) PyObject *bimod = NULL; PyObject *m; PyObject *std = NULL; - int status = 0; + int status = 0, fd; /* Hack to avoid a nasty recursion issue when Python is invoked in verbose mode: pre-import the Latin-1 and UTF-8 codecs */ @@ -748,35 +748,72 @@ initstdio(void) } /* Set sys.stdin */ - if (!(std = PyFile_FromFd(fileno(stdin), "", "r", -1, - NULL, "\n", 0))) { + fd = fileno(stdin); + /* Under some conditions stdin, stdout and stderr may not be connected + * and fileno() may point to an invalid file descriptor. For example + * GUI apps don't have valid standard streams by default. + */ + if (fd < 0) { +#ifdef MS_WINDOWS + std = Py_None; + Py_INCREF(std); +#else goto error; +#endif } + else { + if (!(std = PyFile_FromFd(fd, "", "r", -1, NULL, + "\n", 0))) { + goto error; + } + } /* if (fd < 0) */ PySys_SetObject("__stdin__", std); PySys_SetObject("stdin", std); Py_DECREF(std); /* Set sys.stdout */ - if (!(std = PyFile_FromFd(fileno(stdout), "", "w", -1, - NULL, "\n", 0))) { - goto error; - } + fd = fileno(stdout); + if (fd < 0) { +#ifdef MS_WINDOWS + std = Py_None; + Py_INCREF(std); +#else + goto error; +#endif + } + else { + if (!(std = PyFile_FromFd(fd, "", "w", -1, NULL, + "\n", 0))) { + goto error; + } + } /* if (fd < 0) */ PySys_SetObject("__stdout__", std); PySys_SetObject("stdout", std); Py_DECREF(std); #if 1 /* Disable this if you have trouble debugging bootstrap stuff */ /* Set sys.stderr, replaces the preliminary stderr */ - if (!(std = PyFile_FromFd(fileno(stderr), "", "w", -1, - NULL, "\n", 0))) { - goto error; - } + fd = fileno(stderr); + if (fd < 0) { +#ifdef MS_WINDOWS + std = Py_None; + Py_INCREF(std); +#else + goto error; +#endif + } + else { + if (!(std = PyFile_FromFd(fd, "", "w", -1, NULL, + "\n", 0))) { + goto error; + } + } /* if (fd < 0) */ PySys_SetObject("__stderr__", std); PySys_SetObject("stderr", std); Py_DECREF(std); #endif - if (0) { + if (0) { error: status = -1; }