diff --git a/Doc/library/os.rst b/Doc/library/os.rst index bae432d33b0bd4..b71e210934ef00 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -741,6 +741,9 @@ as internal buffering of data. ` by default or non-inheritable if *inheritable* is ``False``. + If *fd* is valid and equal to *fd2*, this function has no effect + regardless of the value of *inheritable*. + .. versionchanged:: 3.4 Add the optional *inheritable* parameter. diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 77e4a008ae61e8..81d58ced068180 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3102,6 +3102,18 @@ def test_dup2(self): self.assertEqual(os.dup2(fd, fd3, inheritable=False), fd3) self.assertFalse(os.get_inheritable(fd3)) + # dup2(fd, fd) must have no effect for a valid fd + # Issue #26935: Avoid failure due to a bionic bug + # in old Android. + if (not hasattr(sys, 'getandroidapilevel') or + sys.getandroidapilevel() >= 23): + os.set_inheritable(fd, True) + os.dup2(fd, fd, inheritable=False) + self.assertTrue(os.get_inheritable(fd)) + os.set_inheritable(fd, False) + os.dup2(fd, fd, inheritable=True) + self.assertFalse(os.get_inheritable(fd)) + @unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()") def test_openpty(self): master_fd, slave_fd = os.openpty() diff --git a/Misc/NEWS.d/next/Library/2018-02-28-12-36-16.bpo-32862.CUwrAr.rst b/Misc/NEWS.d/next/Library/2018-02-28-12-36-16.bpo-32862.CUwrAr.rst new file mode 100644 index 00000000000000..31b807c5891698 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-02-28-12-36-16.bpo-32862.CUwrAr.rst @@ -0,0 +1 @@ +Make os.dup2(fd, fd) have no effect apart from validating fd. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d242df0b6f3106..ee581edac5d0b9 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8041,7 +8041,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) res = fd2; // msvcrt dup2 returns 0 on success. /* Character files like console cannot be make non-inheritable */ - if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) { + if (!inheritable && fd != fd2 && _Py_set_inheritable(fd2, 0, NULL) < 0) { close(fd2); return -1; } @@ -8061,7 +8061,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) #else #ifdef HAVE_DUP3 - if (!inheritable && dup3_works != 0) { + if (!inheritable && fd != fd2 && dup3_works != 0) { Py_BEGIN_ALLOW_THREADS res = dup3(fd, fd2, O_CLOEXEC); Py_END_ALLOW_THREADS @@ -8075,7 +8075,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) } } - if (inheritable || dup3_works == 0) + if (inheritable || fd == fd2 || dup3_works == 0) { #endif Py_BEGIN_ALLOW_THREADS @@ -8086,7 +8086,8 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) return -1; } - if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) { + if (!inheritable && fd != fd2 && _Py_set_inheritable(fd2, 0, NULL) < 0) + { close(fd2); return -1; }