diff options
-rw-r--r-- | Lib/test/test_cmd_line.py | 39 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | 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 52e715c..70dfb17 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -285,6 +285,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) @@ -10,6 +10,10 @@ What's New in Python 3.3 Alpha 1? 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 #11849: Ensure that free()d memory arenas are really released on POSIX systems supporting anonymous memory mappings. Patch by Charles-François Natali. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 4956943..abc9ffc 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -912,6 +912,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) @@ -971,13 +984,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, "<stdin>", encoding, errors); @@ -990,13 +999,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, "<stdout>", encoding, errors); @@ -1010,13 +1015,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, "<stderr>", encoding, "backslashreplace"); |