summaryrefslogtreecommitdiffstats
path: root/Lib/multiprocessing/popen_spawn_win32.py
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2018-06-27 09:40:24 (GMT)
committerGitHub <noreply@github.com>2018-06-27 09:40:24 (GMT)
commit2cc9d21fffb8146d30e6fb4221e32410ba4b4ab7 (patch)
treea64c215f6670bd22695f9d1855956aa3d57a87e1 /Lib/multiprocessing/popen_spawn_win32.py
parentf15f66d275d1166839312c9ff3a67c00b486c7d6 (diff)
downloadcpython-2cc9d21fffb8146d30e6fb4221e32410ba4b4ab7.zip
cpython-2cc9d21fffb8146d30e6fb4221e32410ba4b4ab7.tar.gz
cpython-2cc9d21fffb8146d30e6fb4221e32410ba4b4ab7.tar.bz2
bpo-33929: multiprocessing: fix handle leak on race condition (GH-7921)
Fix a race condition in Popen of multiprocessing.popen_spawn_win32. The child process now duplicates the read end of pipe instead of "stealing" it. Previously, the read end of pipe was "stolen" by the child process, but it leaked a handle if the child process had been terminated before it could steal the handle from the parent process.
Diffstat (limited to 'Lib/multiprocessing/popen_spawn_win32.py')
-rw-r--r--Lib/multiprocessing/popen_spawn_win32.py15
1 files changed, 13 insertions, 2 deletions
diff --git a/Lib/multiprocessing/popen_spawn_win32.py b/Lib/multiprocessing/popen_spawn_win32.py
index 3e42e9c..3b92c8a 100644
--- a/Lib/multiprocessing/popen_spawn_win32.py
+++ b/Lib/multiprocessing/popen_spawn_win32.py
@@ -18,6 +18,12 @@ TERMINATE = 0x10000
WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
+
+def _close_handles(*handles):
+ for handle in handles:
+ _winapi.CloseHandle(handle)
+
+
#
# We define a Popen class similar to the one from subprocess, but
# whose constructor takes a process object as its argument.
@@ -32,8 +38,12 @@ class Popen(object):
def __init__(self, process_obj):
prep_data = spawn.get_preparation_data(process_obj._name)
- # read end of pipe will be "stolen" by the child process
+ # read end of pipe will be duplicated by the child process
# -- see spawn_main() in spawn.py.
+ #
+ # bpo-33929: Previously, the read end of pipe was "stolen" by the child
+ # process, but it leaked a handle if the child process had been
+ # terminated before it could steal the handle from the parent process.
rhandle, whandle = _winapi.CreatePipe(None, 0)
wfd = msvcrt.open_osfhandle(whandle, 0)
cmd = spawn.get_command_line(parent_pid=os.getpid(),
@@ -56,7 +66,8 @@ class Popen(object):
self.returncode = None
self._handle = hp
self.sentinel = int(hp)
- self.finalizer = util.Finalize(self, _winapi.CloseHandle, (self.sentinel,))
+ self.finalizer = util.Finalize(self, _close_handles,
+ (self.sentinel, int(rhandle)))
# send information to child
set_spawning_popen(self)