Repository navigation
gh-77043: Make os.dup2(fd, fd) a no-op for valid fd #5713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this test into a separated method and emit somehow a SkipTest exception to record that the test is skipped on old Android versions. |
||||||
| # Issue #26935: Avoid failure due to a bionic bug | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I believe it's preferred to use |
||||||
| # in old Android. | ||||||
| if (not hasattr(sys, 'getandroidapilevel') or | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this new test code should be placed in a new method. The Android checks should be put in a |
||||||
| 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() | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Make os.dup2(fd, fd) have no effect apart from validating fd. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8041,7 +8041,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) | |
| res = fd2; // msvcrt dup2 returns 0 on success. | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please document somewhere the rationale for "fd != fd2" tests with a reference to "bpo-32862". |
||
| /* 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; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a
versionchangeddirective.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"this function has no effect": that's wrong, it does validate the FD which is a legit usage of this function. I would rather remove this sentence.