Issue #18571: Implementation of the PEP 446: file descriptors and file handles
are now created non-inheritable; add functions os.get/set_inheritable(),
os.get/set_handle_inheritable() and socket.socket.get/set_inheritable().
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index 137ebcb..7ce86a4 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -129,6 +129,8 @@
     be kept open when the file is closed. This does not work when a file name is
     given and must be True in that case.
 
+    The newly created file is non-inheritable.
+
     A custom opener can be used by passing a callable as *opener*. The
     underlying file descriptor for the file object is then obtained by calling
     *opener* with (*file*, *flags*). *opener* must return an open file
diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
index 443fa7e..9fbe46d 100644
--- a/Lib/multiprocessing/connection.py
+++ b/Lib/multiprocessing/connection.py
@@ -509,7 +509,7 @@
             c1 = Connection(s1.detach())
             c2 = Connection(s2.detach())
         else:
-            fd1, fd2 = util.pipe()
+            fd1, fd2 = os.pipe()
             c1 = Connection(fd1, writable=False)
             c2 = Connection(fd2, readable=False)
 
@@ -536,7 +536,9 @@
             _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE,
             _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE |
             _winapi.PIPE_WAIT,
-            1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL
+            1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER,
+            # default security descriptor: the handle cannot be inherited
+            _winapi.NULL
             )
         h2 = _winapi.CreateFile(
             address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,
diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py
index 208bd4e..11df382 100644
--- a/Lib/multiprocessing/forkserver.py
+++ b/Lib/multiprocessing/forkserver.py
@@ -60,8 +60,8 @@
         raise ValueError('too many fds')
     with socket.socket(socket.AF_UNIX) as client:
         client.connect(_forkserver_address)
-        parent_r, child_w = util.pipe()
-        child_r, parent_w = util.pipe()
+        parent_r, child_w = os.pipe()
+        child_r, parent_w = os.pipe()
         allfds = [child_r, child_w, _forkserver_alive_fd,
                   semaphore_tracker._semaphore_tracker_fd]
         allfds += fds
diff --git a/Lib/multiprocessing/popen_fork.py b/Lib/multiprocessing/popen_fork.py
index fd25ddc..c9f3aae 100644
--- a/Lib/multiprocessing/popen_fork.py
+++ b/Lib/multiprocessing/popen_fork.py
@@ -66,7 +66,7 @@
 
     def _launch(self, process_obj):
         code = 1
-        parent_r, child_w = util.pipe()
+        parent_r, child_w = os.pipe()
         self.pid = os.fork()
         if self.pid == 0:
             try:
diff --git a/Lib/multiprocessing/popen_spawn_posix.py b/Lib/multiprocessing/popen_spawn_posix.py
index e67915d..751bf22 100644
--- a/Lib/multiprocessing/popen_spawn_posix.py
+++ b/Lib/multiprocessing/popen_spawn_posix.py
@@ -54,8 +54,8 @@
 
         parent_r = child_w = child_r = parent_w = None
         try:
-            parent_r, child_w = util.pipe()
-            child_r, parent_w = util.pipe()
+            parent_r, child_w = os.pipe()
+            child_r, parent_w = os.pipe()
             cmd = spawn.get_command_line(tracker_fd=tracker_fd,
                                          pipe_handle=child_r)
             self._fds.extend([child_r, child_w])
diff --git a/Lib/multiprocessing/semaphore_tracker.py b/Lib/multiprocessing/semaphore_tracker.py
index 99a0dd4..6c9e4a5 100644
--- a/Lib/multiprocessing/semaphore_tracker.py
+++ b/Lib/multiprocessing/semaphore_tracker.py
@@ -45,7 +45,7 @@
         except Exception:
             pass
         cmd = 'from multiprocessing.semaphore_tracker import main; main(%d)'
-        r, w = util.pipe()
+        r, w = os.pipe()
         try:
             fds_to_pass.append(r)
             # process will out live us, so no need to wait on pid
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
index d9e4799..ac8e913 100644
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -365,7 +365,7 @@
         if flag & fcntl.FD_CLOEXEC:
             fcntl.fcntl(fd, fcntl.F_SETFD, flag & ~fcntl.FD_CLOEXEC)
             tmp.append((fd, flag))
-    errpipe_read, errpipe_write = _posixsubprocess.cloexec_pipe()
+    errpipe_read, errpipe_write = os.pipe()
     try:
         return _posixsubprocess.fork_exec(
             args, [os.fsencode(path)], True, passfds, None, None,
@@ -381,7 +381,9 @@
 #
 # Return pipe with CLOEXEC set on fds
 #
+# Deprecated: os.pipe() creates non-inheritable file descriptors
+# since Python 3.4
+#
 
 def pipe():
-    import _posixsubprocess
-    return _posixsubprocess.cloexec_pipe()
+    return os.pipe()
diff --git a/Lib/socket.py b/Lib/socket.py
index 96f8ed0..81864f5 100644
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -137,7 +137,8 @@
     def dup(self):
         """dup() -> socket object
 
-        Return a new socket object connected to the same system resource.
+        Duplicate the socket. Return a new socket object connected to the same
+        system resource. The new socket is non-inheritable.
         """
         fd = dup(self.fileno())
         sock = self.__class__(self.family, self.type, self.proto, fileno=fd)
@@ -229,6 +230,20 @@
         self._closed = True
         return super().detach()
 
+    if os.name == 'nt':
+        def get_inheritable(self):
+            return os.get_handle_inheritable(self.fileno())
+        def set_inheritable(self, inheritable):
+            os.set_handle_inheritable(self.fileno(), inheritable)
+    else:
+        def get_inheritable(self):
+            return os.get_inheritable(self.fileno())
+        def set_inheritable(self, inheritable):
+            os.set_inheritable(self.fileno(), inheritable)
+    get_inheritable.__doc__ = "Get the inheritable flag of the socket"
+    set_inheritable.__doc__ = "Set the inheritable flag of the socket"
+
+
 def fromfd(fd, family, type, proto=0):
     """ fromfd(fd, family, type[, proto]) -> socket object
 
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 6ebcc25..4ce3c92 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -405,7 +405,6 @@
     import select
     _has_poll = hasattr(select, 'poll')
     import _posixsubprocess
-    _create_pipe = _posixsubprocess.cloexec_pipe
 
     # When select or poll has indicated that the file is writable,
     # we can write up to _PIPE_BUF bytes without risk of blocking.
@@ -1258,7 +1257,7 @@
             if stdin is None:
                 pass
             elif stdin == PIPE:
-                p2cread, p2cwrite = _create_pipe()
+                p2cread, p2cwrite = os.pipe()
             elif stdin == DEVNULL:
                 p2cread = self._get_devnull()
             elif isinstance(stdin, int):
@@ -1270,7 +1269,7 @@
             if stdout is None:
                 pass
             elif stdout == PIPE:
-                c2pread, c2pwrite = _create_pipe()
+                c2pread, c2pwrite = os.pipe()
             elif stdout == DEVNULL:
                 c2pwrite = self._get_devnull()
             elif isinstance(stdout, int):
@@ -1282,7 +1281,7 @@
             if stderr is None:
                 pass
             elif stderr == PIPE:
-                errread, errwrite = _create_pipe()
+                errread, errwrite = os.pipe()
             elif stderr == STDOUT:
                 errwrite = c2pwrite
             elif stderr == DEVNULL:
@@ -1334,7 +1333,7 @@
             # For transferring possible exec failure from child to parent.
             # Data format: "exception name:hex errno:description"
             # Pickle is not used; it is complex and involves memory allocation.
-            errpipe_read, errpipe_write = _create_pipe()
+            errpipe_read, errpipe_write = os.pipe()
             try:
                 try:
                     # We must avoid complex work that could involve
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index df73289..1eff59c 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -35,33 +35,12 @@
 from random import Random as _Random
 
 try:
-    import fcntl as _fcntl
-except ImportError:
-    def _set_cloexec(fd):
-        pass
-else:
-    def _set_cloexec(fd):
-        try:
-            flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
-        except OSError:
-            pass
-        else:
-            # flags read successfully, modify
-            flags |= _fcntl.FD_CLOEXEC
-            _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
-
-
-try:
     import _thread
 except ImportError:
     import _dummy_thread as _thread
 _allocate_lock = _thread.allocate_lock
 
 _text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
-if hasattr(_os, 'O_CLOEXEC'):
-    _text_openflags |= _os.O_CLOEXEC
-if hasattr(_os, 'O_NOINHERIT'):
-    _text_openflags |= _os.O_NOINHERIT
 if hasattr(_os, 'O_NOFOLLOW'):
     _text_openflags |= _os.O_NOFOLLOW
 
@@ -90,8 +69,8 @@
     # Fallback.  All we need is something that raises OSError if the
     # file doesn't exist.
     def _stat(fn):
-        f = open(fn)
-        f.close()
+        fd = _os.open(fn, _os.O_RDONLY)
+        os.close(fd)
 
 def _exists(fn):
     try:
@@ -217,7 +196,6 @@
         file = _os.path.join(dir, pre + name + suf)
         try:
             fd = _os.open(file, flags, 0o600)
-            _set_cloexec(fd)
             return (fd, _os.path.abspath(file))
         except FileExistsError:
             continue    # try again
diff --git a/Lib/test/subprocessdata/inherited.py b/Lib/test/subprocessdata/inherited.py
new file mode 100644
index 0000000..1aac041
--- /dev/null
+++ b/Lib/test/subprocessdata/inherited.py
@@ -0,0 +1,22 @@
+"""Similar to fd_status.py, but only checks file descriptors passed on the
+command line."""
+
+import errno
+import os
+import sys
+import stat
+
+if __name__ == "__main__":
+    fds = map(int, sys.argv[1:])
+    inherited = []
+    for fd in fds:
+        try:
+            st = os.fstat(fd)
+        except OSError as e:
+            if e.errno == errno.EBADF:
+                continue
+            raise
+        # Ignore Solaris door files
+        if not stat.S_ISDOOR(st.st_mode):
+            inherited.append(fd)
+    print(','.join(map(str, inherited)))
diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py
index 87655f4..084d247 100644
--- a/Lib/test/test_asyncore.py
+++ b/Lib/test/test_asyncore.py
@@ -744,7 +744,12 @@
         s.create_socket(self.family)
         self.assertEqual(s.socket.family, self.family)
         SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
-        self.assertEqual(s.socket.type, socket.SOCK_STREAM | SOCK_NONBLOCK)
+        sock_type = socket.SOCK_STREAM | SOCK_NONBLOCK
+        if hasattr(socket, 'SOCK_CLOEXEC'):
+            self.assertIn(s.socket.type,
+                          (sock_type | socket.SOCK_CLOEXEC, sock_type))
+        else:
+            self.assertEqual(s.socket.type, sock_type)
 
     def test_bind(self):
         if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 8d3271f..2411c9b 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -1015,6 +1015,11 @@
             os.environ.clear()
             os.environ.update(old_environ)
 
+    def test_open_non_inheritable(self):
+        fileobj = open(__file__)
+        with fileobj:
+            self.assertFalse(os.get_inheritable(fileobj.fileno()))
+
     def test_ord(self):
         self.assertEqual(ord(' '), 32)
         self.assertEqual(ord('A'), 65)
diff --git a/Lib/test/test_devpoll.py b/Lib/test/test_devpoll.py
index 167e0ee..40ebeee 100644
--- a/Lib/test/test_devpoll.py
+++ b/Lib/test/test_devpoll.py
@@ -2,7 +2,11 @@
 
 # Initial tests are copied as is from "test_poll.py"
 
-import os, select, random, unittest, sys
+import os
+import random
+import select
+import sys
+import unittest
 from test.support import TESTFN, run_unittest
 
 try:
@@ -111,6 +115,11 @@
         self.assertRaises(ValueError, devpoll.register, fd, fd, select.POLLIN)
         self.assertRaises(ValueError, devpoll.unregister, fd)
 
+    def test_fd_non_inheritable(self):
+        devpoll = select.devpoll()
+        self.addCleanup(devpoll.close)
+        self.assertEqual(os.get_inheritable(devpoll.fileno()), False)
+
 
 def test_main():
     run_unittest(DevPollTests)
diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py
index 93a9e1d..6459fba 100644
--- a/Lib/test/test_epoll.py
+++ b/Lib/test/test_epoll.py
@@ -21,10 +21,11 @@
 """
 Tests for epoll wrapper.
 """
-import socket
 import errno
-import time
+import os
 import select
+import socket
+import time
 import unittest
 
 from test import support
@@ -249,6 +250,11 @@
         self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN)
         self.assertRaises(ValueError, epoll.unregister, fd)
 
+    def test_fd_non_inheritable(self):
+        epoll = select.epoll()
+        self.addCleanup(epoll.close)
+        self.assertEqual(os.get_inheritable(epoll.fileno()), False)
+
 
 def test_main():
     support.run_unittest(TestEPoll)
diff --git a/Lib/test/test_kqueue.py b/Lib/test/test_kqueue.py
index 930f088..bafdeba 100644
--- a/Lib/test/test_kqueue.py
+++ b/Lib/test/test_kqueue.py
@@ -206,6 +206,11 @@
         # operations must fail with ValueError("I/O operation on closed ...")
         self.assertRaises(ValueError, kqueue.control, None, 4)
 
+    def test_fd_non_inheritable(self):
+        kqueue = select.kqueue()
+        self.addCleanup(kqueue.close)
+        self.assertEqual(os.get_inheritable(kqueue.fileno()), False)
+
 
 def test_main():
     support.run_unittest(TestKQueue)
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 1d41b77..d0dd364 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -2298,6 +2298,72 @@
         else:
             self.skipTest("Could not determine the number of CPUs")
 
+
+class FDInheritanceTests(unittest.TestCase):
+    def test_get_inheritable(self):
+        fd = os.open(__file__, os.O_RDONLY)
+        self.addCleanup(os.close, fd)
+        for inheritable in (False, True):
+            os.set_inheritable(fd, inheritable)
+            self.assertEqual(os.get_inheritable(fd), inheritable)
+
+    def test_set_inheritable(self):
+        fd = os.open(__file__, os.O_RDONLY)
+        self.addCleanup(os.close, fd)
+        os.set_inheritable(fd, True)
+        self.assertEqual(os.get_inheritable(fd), True)
+
+    def test_open(self):
+        fd = os.open(__file__, os.O_RDONLY)
+        self.addCleanup(os.close, fd)
+        self.assertEqual(os.get_inheritable(fd), False)
+
+    @unittest.skipUnless(hasattr(os, 'pipe'), "need os.pipe()")
+    def test_pipe(self):
+        rfd, wfd = os.pipe()
+        self.addCleanup(os.close, rfd)
+        self.addCleanup(os.close, wfd)
+        self.assertEqual(os.get_inheritable(rfd), False)
+        self.assertEqual(os.get_inheritable(wfd), False)
+
+    def test_dup(self):
+        fd1 = os.open(__file__, os.O_RDONLY)
+        self.addCleanup(os.close, fd1)
+
+        fd2 = os.dup(fd1)
+        self.addCleanup(os.close, fd2)
+        self.assertEqual(os.get_inheritable(fd2), False)
+
+    @unittest.skipUnless(hasattr(os, 'dup2'), "need os.dup2()")
+    def test_dup2(self):
+        fd = os.open(__file__, os.O_RDONLY)
+        self.addCleanup(os.close, fd)
+
+        # inheritable by default
+        fd2 = os.open(__file__, os.O_RDONLY)
+        try:
+            os.dup2(fd, fd2)
+            self.assertEqual(os.get_inheritable(fd2), True)
+        finally:
+            os.close(fd2)
+
+        # force non-inheritable
+        fd3 = os.open(__file__, os.O_RDONLY)
+        try:
+            os.dup2(fd, fd3, inheritable=False)
+            self.assertEqual(os.get_inheritable(fd3), False)
+        finally:
+            os.close(fd3)
+
+    @unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
+    def test_openpty(self):
+        master_fd, slave_fd = os.openpty()
+        self.addCleanup(os.close, master_fd)
+        self.addCleanup(os.close, slave_fd)
+        self.assertEqual(os.get_inheritable(master_fd), False)
+        self.assertEqual(os.get_inheritable(slave_fd), False)
+
+
 @support.reap_threads
 def test_main():
     support.run_unittest(
@@ -2330,6 +2396,7 @@
         OSErrorTests,
         RemoveDirsTests,
         CPUCountTests,
+        FDInheritanceTests,
     )
 
 if __name__ == "__main__":
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index c7a52d8..c7b9ba8 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -23,10 +23,6 @@
 import pickle
 import struct
 try:
-    import fcntl
-except ImportError:
-    fcntl = False
-try:
     import multiprocessing
 except ImportError:
     multiprocessing = False
@@ -1108,9 +1104,15 @@
 
     def testNewAttributes(self):
         # testing .family, .type and .protocol
+
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.assertEqual(sock.family, socket.AF_INET)
-        self.assertEqual(sock.type, socket.SOCK_STREAM)
+        if hasattr(socket, 'SOCK_CLOEXEC'):
+            self.assertIn(sock.type,
+                          (socket.SOCK_STREAM | socket.SOCK_CLOEXEC,
+                           socket.SOCK_STREAM))
+        else:
+            self.assertEqual(sock.type, socket.SOCK_STREAM)
         self.assertEqual(sock.proto, 0)
         sock.close()
 
@@ -4749,16 +4751,46 @@
         self.assertRaises(OSError, sock.sendall, b'foo')
 
 
-@unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),
-                     "SOCK_CLOEXEC not defined")
-@unittest.skipUnless(fcntl, "module fcntl not available")
-class CloexecConstantTest(unittest.TestCase):
+class InheritanceTest(unittest.TestCase):
+    @unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),
+                         "SOCK_CLOEXEC not defined")
     @support.requires_linux_version(2, 6, 28)
     def test_SOCK_CLOEXEC(self):
         with socket.socket(socket.AF_INET,
                            socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as s:
             self.assertTrue(s.type & socket.SOCK_CLOEXEC)
-            self.assertTrue(fcntl.fcntl(s, fcntl.F_GETFD) & fcntl.FD_CLOEXEC)
+            self.assertTrue(sock.get_inheritable())
+
+    def test_default_inheritable(self):
+        sock = socket.socket()
+        with sock:
+            self.assertEqual(sock.get_inheritable(), False)
+
+    def test_dup(self):
+        sock = socket.socket()
+        with sock:
+            newsock = sock.dup()
+            sock.close()
+            with newsock:
+                self.assertEqual(newsock.get_inheritable(), False)
+
+    def test_set_inheritable(self):
+        sock = socket.socket()
+        with sock:
+            sock.set_inheritable(True)
+            self.assertEqual(sock.get_inheritable(), True)
+
+            sock.set_inheritable(False)
+            self.assertEqual(sock.get_inheritable(), False)
+
+    @unittest.skipUnless(hasattr(socket, "socketpair"),
+                         "need socket.socketpair()")
+    def test_socketpair(self):
+        s1, s2 = socket.socketpair()
+        self.addCleanup(s1.close)
+        self.addCleanup(s2.close)
+        self.assertEqual(s1.get_inheritable(), False)
+        self.assertEqual(s2.get_inheritable(), False)
 
 
 @unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"),
@@ -4927,7 +4959,7 @@
         NetworkConnectionAttributesTest,
         NetworkConnectionBehaviourTest,
         ContextManagersTest,
-        CloexecConstantTest,
+        InheritanceTest,
         NonblockConstantTest
     ])
     if hasattr(socket, "socketpair"):
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 8a3ac4b..8cd2d1e 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -1501,16 +1501,28 @@
         # Terminating a dead process
         self._kill_dead_process('terminate')
 
+    def _save_fds(self, save_fds):
+        fds = []
+        for fd in save_fds:
+            inheritable = os.get_inheritable(fd)
+            saved = os.dup(fd)
+            fds.append((fd, saved, inheritable))
+        return fds
+
+    def _restore_fds(self, fds):
+        for fd, saved, inheritable in fds:
+            os.dup2(saved, fd, inheritable=inheritable)
+            os.close(saved)
+
     def check_close_std_fds(self, fds):
         # Issue #9905: test that subprocess pipes still work properly with
         # some standard fds closed
         stdin = 0
-        newfds = []
-        for a in fds:
-            b = os.dup(a)
-            newfds.append(b)
-            if a == 0:
-                stdin = b
+        saved_fds = self._save_fds(fds)
+        for fd, saved, inheritable in saved_fds:
+            if fd == 0:
+                stdin = saved
+                break
         try:
             for fd in fds:
                 os.close(fd)
@@ -1525,10 +1537,7 @@
             err = support.strip_python_stderr(err)
             self.assertEqual((out, err), (b'apple', b'orange'))
         finally:
-            for b, a in zip(newfds, fds):
-                os.dup2(b, a)
-            for b in newfds:
-                os.close(b)
+            self._restore_fds(saved_fds)
 
     def test_close_fd_0(self):
         self.check_close_std_fds([0])
@@ -1568,7 +1577,7 @@
             os.lseek(temp_fds[1], 0, 0)
 
             # move the standard file descriptors out of the way
-            saved_fds = [os.dup(fd) for fd in range(3)]
+            saved_fds = self._save_fds(range(3))
             try:
                 # duplicate the file objects over the standard fd's
                 for fd, temp_fd in enumerate(temp_fds):
@@ -1584,10 +1593,7 @@
                     stderr=temp_fds[0])
                 p.wait()
             finally:
-                # restore the original fd's underneath sys.stdin, etc.
-                for std, saved in enumerate(saved_fds):
-                    os.dup2(saved, std)
-                    os.close(saved)
+                self._restore_fds(saved_fds)
 
             for fd in temp_fds:
                 os.lseek(fd, 0, 0)
@@ -1611,7 +1617,7 @@
                 os.unlink(fname)
 
             # save a copy of the standard file descriptors
-            saved_fds = [os.dup(fd) for fd in range(3)]
+            saved_fds = self._save_fds(range(3))
             try:
                 # duplicate the temp files over the standard fd's 0, 1, 2
                 for fd, temp_fd in enumerate(temp_fds):
@@ -1637,9 +1643,7 @@
                 out = os.read(stdout_no, 1024)
                 err = support.strip_python_stderr(os.read(stderr_no, 1024))
             finally:
-                for std, saved in enumerate(saved_fds):
-                    os.dup2(saved, std)
-                    os.close(saved)
+                self._restore_fds(saved_fds)
 
             self.assertEqual(out, b"got STDIN")
             self.assertEqual(err, b"err")
@@ -1810,6 +1814,9 @@
             self.addCleanup(os.close, fd)
             open_fds.add(fd)
 
+        for fd in open_fds:
+            os.set_inheritable(fd, True)
+
         p = subprocess.Popen([sys.executable, fd_status],
                              stdout=subprocess.PIPE, close_fds=False)
         output, ignored = p.communicate()
@@ -1854,6 +1861,8 @@
             fds = os.pipe()
             self.addCleanup(os.close, fds[0])
             self.addCleanup(os.close, fds[1])
+            os.set_inheritable(fds[0], True)
+            os.set_inheritable(fds[1], True)
             open_fds.update(fds)
 
         for fd in open_fds:
@@ -1876,6 +1885,32 @@
                         close_fds=False, pass_fds=(fd, )))
             self.assertIn('overriding close_fds', str(context.warning))
 
+    def test_pass_fds_inheritable(self):
+        script = support.findfile("inherited.py", subdir="subprocessdata")
+
+        inheritable, non_inheritable = os.pipe()
+        self.addCleanup(os.close, inheritable)
+        self.addCleanup(os.close, non_inheritable)
+        os.set_inheritable(inheritable, True)
+        os.set_inheritable(non_inheritable, False)
+        pass_fds = (inheritable, non_inheritable)
+        args = [sys.executable, script]
+        args += list(map(str, pass_fds))
+
+        p = subprocess.Popen(args,
+                             stdout=subprocess.PIPE, close_fds=True,
+                             pass_fds=pass_fds)
+        output, ignored = p.communicate()
+        fds = set(map(int, output.split(b',')))
+
+        # the inheritable file descriptor must be inherited, so its inheritable
+        # flag must be set in the child process after fork() and before exec()
+        self.assertEqual(fds, set(pass_fds))
+
+        # inheritable flag must not be changed in the parent process
+        self.assertEqual(os.get_inheritable(inheritable), True)
+        self.assertEqual(os.get_inheritable(non_inheritable), False)
+
     def test_stdout_stdin_are_single_inout_fd(self):
         with io.open(os.devnull, "r+") as inout:
             p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 6b146d2..493c640 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -333,6 +333,7 @@
             v="q"
 
         file = self.do_create()
+        self.assertEqual(os.get_inheritable(file.fd), False)
         fd = "%d" % file.fd
 
         try:
diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py
index 78ca4e0..d914282 100644
--- a/Lib/xmlrpc/server.py
+++ b/Lib/xmlrpc/server.py
@@ -584,13 +584,6 @@
         SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding, use_builtin_types)
         socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate)
 
-        # [Bug #1222790] If possible, set close-on-exec flag; if a
-        # method spawns a subprocess, the subprocess shouldn't have
-        # the listening socket open.
-        if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
-            flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
-            flags |= fcntl.FD_CLOEXEC
-            fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
 
 class MultiPathXMLRPCServer(SimpleXMLRPCServer):
     """Multipath XML-RPC Server