From 11942a58a190a235f69e8fb193d08a4fca2bcf3c Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 28 Nov 2011 19:08:36 +0100 Subject: Issue #7111: Python can now be run without a stdin, stdout or stderr stream. It was already the case with Python 2. However, the corresponding sys module entries are now set to None (instead of an unusable file object). --- Lib/test/test_cmd_line.py | 39 +++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 4 ++++ Python/pythonrun.c | 31 ++++++++++++++++--------------- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 8167e78..2fca25e 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -291,6 +291,45 @@ class CmdLineTest(unittest.TestCase): rc, out, err = assert_python_ok('-c', code) self.assertEqual(b'', err) + # Issue #7111: Python should work without standard streams + + @unittest.skipIf(os.name != 'posix', "test needs POSIX semantics") + def _test_no_stdio(self, streams): + code = """if 1: + import os, sys + for i, s in enumerate({streams}): + if getattr(sys, s) is not None: + os._exit(i + 1) + os._exit(42)""".format(streams=streams) + def preexec(): + if 'stdin' in streams: + os.close(0) + if 'stdout' in streams: + os.close(1) + if 'stderr' in streams: + os.close(2) + p = subprocess.Popen( + [sys.executable, "-E", "-c", code], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + preexec_fn=preexec) + out, err = p.communicate() + self.assertEqual(test.support.strip_python_stderr(err), b'') + self.assertEqual(p.returncode, 42) + + def test_no_stdin(self): + self._test_no_stdio(['stdin']) + + def test_no_stdout(self): + self._test_no_stdio(['stdout']) + + def test_no_stderr(self): + self._test_no_stdio(['stderr']) + + def test_no_std_streams(self): + self._test_no_stdio(['stdin', 'stdout', 'stderr']) + def test_main(): test.support.run_unittest(CmdLineTest) diff --git a/Misc/NEWS b/Misc/NEWS index 3041a73..f79e57a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 3.2.3? Core and Builtins ----------------- +- Issue #7111: Python can now be run without a stdin, stdout or stderr + stream. It was already the case with Python 2. However, the corresponding + sys module entries are now set to None (instead of an unusable file object). + - Issue #13436: Fix a bogus error message when an AST object was passed an invalid integer value. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index fe92d30..4b0ac13 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -892,6 +892,19 @@ error: return NULL; } +static int +is_valid_fd(int fd) +{ + int dummy_fd; + if (fd < 0 || !_PyVerify_fd(fd)) + return 0; + dummy_fd = dup(fd); + if (dummy_fd < 0) + return 0; + close(dummy_fd); + return 1; +} + /* Initialize sys.stdin, stdout, stderr and builtins.open */ static int initstdio(void) @@ -951,13 +964,9 @@ initstdio(void) * 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 + if (!is_valid_fd(fd)) { std = Py_None; Py_INCREF(std); -#else - goto error; -#endif } else { std = create_stdio(iomod, fd, 0, "", encoding, errors); @@ -970,13 +979,9 @@ initstdio(void) /* Set sys.stdout */ fd = fileno(stdout); - if (fd < 0) { -#ifdef MS_WINDOWS + if (!is_valid_fd(fd)) { std = Py_None; Py_INCREF(std); -#else - goto error; -#endif } else { std = create_stdio(iomod, fd, 1, "", encoding, errors); @@ -990,13 +995,9 @@ initstdio(void) #if 1 /* Disable this if you have trouble debugging bootstrap stuff */ /* Set sys.stderr, replaces the preliminary stderr */ fd = fileno(stderr); - if (fd < 0) { -#ifdef MS_WINDOWS + if (!is_valid_fd(fd)) { std = Py_None; Py_INCREF(std); -#else - goto error; -#endif } else { std = create_stdio(iomod, fd, 1, "", encoding, "backslashreplace"); -- cgit v0.12