10000 return the new file descriptor from os.dup2 (closes bpo-32441) (#5041) · python/cpython@bbdb17d · GitHub
[go: up one dir, main page]

Skip to content

Commit bbdb17d

Browse files
authored
return the new file descriptor from os.dup2 (closes bpo-32441) (#5041)
1 parent 03220fd commit bbdb17d

File tree

5 files changed

+50
-32
lines changed

5 files changed

+50
-32
lines changed

Doc/library/os.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -735,13 +735,17 @@ as internal buffering of data.
735735

736736
.. function:: dup2(fd, fd2, inheritable=True)
737737

738-
Duplicate file descriptor *fd* to *fd2*, closing the latter first if necessary.
739-
The file descriptor *fd2* is :ref:`inheritable <fd_inheritance>` by default,
740-
or non-inheritable if *inheritable* is ``False``.
738+
Duplicate file descriptor *fd* to *fd2*, closing the latter first if
739+
necessary. Return *fd2*. The new file descriptor is :ref:`inheritable
740+
<fd_inheritance>` by default or non-inheritable if *inheritable*
741+
is ``False``.
741742

742743
.. versionchanged:: 3.4
743744
Add the optional *inheritable* parameter.
744745

746+
.. versionchanged:: 3.7
747+
Return *fd2* on success. Previously, ``None`` was always returned.
748+
745749

746750
.. function:: fchmod(fd, mode)
747751

Lib/test/test_os.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3079,19 +3079,15 @@ def test_dup2(self):
30793079

30803080
# inheritable by default
30813081
fd2 = os.open(__file__, os.O_RDONLY)
3082-
try:
3083-
os.dup2(fd, fd2)
3084-
self.assertEqual(os.get_inheritable(fd2), True)
3085-
finally:
3086-
os.close(fd2)
3082+
self.addCleanup(os.close, fd2)
3083+
self.assertEqual(os.dup2(fd, fd2), fd2)
3084+
self.assertTrue(os.get_inheritable(fd2))
30873085

30883086
# force non-inheritable
30893087
fd3 = os.open(__file__, os.O_RDONLY)
3090-
try:
3091-
os.dup2(fd, fd3, inheritable=False)
3092-
self.assertEqual(os.get_inheritable(fd3), False)
3093-
finally:
3094-
os.close(fd3)
3088+
self.addCleanup(os.close, fd3)
3089+
self.assertEqual(os.dup2(fd, fd3, inheritable=False), fd3)
3090+
self.assertFalse(os.get_inheritable(fd3))
30953091

30963092
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
30973093
def test_openpty(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Return the new file descriptor (i.e., the second argument) from ``os.dup2``.
2+
Previously, ``None`` was always returned.

Modules/clinic/posixmodule.c.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3486,7 +3486,7 @@ PyDoc_STRVAR(os_dup2__doc__,
34863486
#define OS_DUP2_METHODDEF \
34873487
{"dup2", (PyCFunction)os_dup2, METH_FASTCALL|METH_KEYWORDS, os_dup2__doc__},
34883488

3489-
static PyObject *
3489+
static int
34903490
os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable);
34913491

34923492
static PyObject *
@@ -3498,12 +3498,17 @@ os_dup2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn
34983498
int fd;
34993499
int fd2;
35003500
int inheritable = 1;
3501+
int _return_value;
35013502

35023503
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
35033504
&fd, &fd2, &inheritable)) {
35043505
goto exit;
35053506
}
3506-
return_value = os_dup2_impl(module, fd, fd2, inheritable);
3507+
_return_value = os_dup2_impl(module, fd, fd2, inheritable);
3508+
if ((_return_value == -1) && PyErr_Occurred()) {
3509+
goto exit;
3510+
}
3511+
return_value = PyLong_FromLong((long)_return_value);
35073512

35083513
exit:
35093514
return return_value;
@@ -6405,4 +6410,4 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
64056410
#ifndef OS_GETRANDOM_METHODDEF
64066411
#define OS_GETRANDOM_METHODDEF
64076412
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
6408-
/*[clinic end generated code: output=b6ade5f170d5a431 input=a9049054013a1b77]*/
6413+
/*[clinic end generated code: output=6345053cd5992caf input=a9049054013a1b77]*/

Modules/posixmodule.c

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7770,17 +7770,17 @@ os_dup_impl(PyObject *module, int fd)
77707770

77717771

77727772
/*[clinic input]
7773-
os.dup2
7773+
os.dup2 -> int
77747774
fd: int
77757775
fd2: int
77767776
inheritable: bool=True
77777777
77787778
Duplicate file descriptor.
77797779
[clinic start generated code]*/
77807780

7781-
static PyObject *
7781+
static int
77827782
os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
7783-
/*[clinic end generated code: output=db832a2d872ccc5f input=76e96f511be0352f]*/
7783+
/*[clinic end generated code: output=bc059d34a73404d1 input=c3cddda8922b038d]*/
77847784
{
77857785
int res;
77867786
#if defined(HAVE_DUP3) && \
@@ -7789,8 +7789,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
77897789
int dup3_works = -1;
77907790
#endif
77917791

7792-
if (fd < 0 || fd2 < 0)
7793-
return posix_error();
7792+
if (fd < 0 || fd2 < 0) {
7793+
posix_error();
7794+
return -1;
7795+
}
77947796

77957797
/* dup2() can fail with EINTR if the target FD is already open, because it
77967798
* then has to be closed. See os_close_impl() for why we don't handle EINTR
@@ -7802,13 +7804,16 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
78027804
res = dup2(fd, fd2);
78037805
_Py_END_SUPPRESS_IPH
78047806
Py_END_ALLOW_THREADS
7805-
if (res < 0)
7806-
return posix_error();
7807+
if (res < 0) {
7808+
posix_error();
7809+
return -1;
7810+
}
7811+
res = fd2; // msvcrt dup2 returns 0 on success.
78077812

78087813
/* Character files like console cannot be make non-inheritable */
78097814
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
78107815
close(fd2);
7811-
return NULL;
7816+
return -1;
78127817
}
78137818

78147819
#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
@@ -7818,8 +7823,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
78187823
else
78197824
res = dup2(fd, fd2);
78207825
Py_END_ALLOW_THREADS
7821-
if (res < 0)
7822-
return posix_error();
7826+
if (res < 0) {
7827+
posix_error();
7828+
return -1;
7829+
}
78237830

78247831
#else
78257832

@@ -7831,8 +7838,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
78317838
if (res < 0) {
78327839
if (dup3_works == -1)
78337840
dup3_works = (errno != ENOSYS);
7834-
if (dup3_works)
7835-
return posix_error();
7841+
if (dup3_works) {
7842+
posix_error();
7843+
return -1;
7844+
}
78367845
}
78377846
}
78387847

@@ -7842,20 +7851,22 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
78427851
Py_BEGIN_ALLOW_THREADS
78437852
res = dup2(fd, fd2);
78447853
Py_END_ALLOW_THREADS
7845-
if (res < 0)
7846-
return posix_error();
7854+
if (res < 0) {
7855+
posix_error();
7856+
return -1;
7857+
}
78477858

78487859
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
78497860
close(fd2);
7850-
return NULL;
7861+
return -1;
78517862
}
78527863
#ifdef HAVE_DUP3
78537864
}
78547865
#endif
78557866

78567867
#endif
78577868

7858-
Py_RETURN_NONE;
7869+
return res;
78597870
}
78607871

78617872

0 commit comments

Comments
 (0)
0