bpo-33929: multiprocessing: fix handle leak on race condition (GH-7921) · python/cpython@8b1ebcd
@@ -18,6 +18,12 @@
1818WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
1919WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
202021+22+def _close_handles(*handles):
23+for handle in handles:
24+_winapi.CloseHandle(handle)
25+26+2127#
2228# We define a Popen class similar to the one from subprocess, but
2329# whose constructor takes a process object as its argument.
@@ -32,8 +38,12 @@ class Popen(object):
3238def __init__(self, process_obj):
3339prep_data = spawn.get_preparation_data(process_obj._name)
344035-# read end of pipe will be "stolen" by the child process
41+# read end of pipe will be duplicated by the child process
3642# -- see spawn_main() in spawn.py.
43+#
44+# bpo-33929: Previously, the read end of pipe was "stolen" by the child
45+# process, but it leaked a handle if the child process had been
46+# terminated before it could steal the handle from the parent process.
3747rhandle, whandle = _winapi.CreatePipe(None, 0)
3848wfd = msvcrt.open_osfhandle(whandle, 0)
3949cmd = spawn.get_command_line(parent_pid=os.getpid(),
@@ -56,7 +66,8 @@ def __init__(self, process_obj):
5666self.returncode = None
5767self._handle = hp
5868self.sentinel = int(hp)
59-self.finalizer = util.Finalize(self, _winapi.CloseHandle, (self.sentinel,))
69+self.finalizer = util.Finalize(self, _close_handles,
70+ (self.sentinel, int(rhandle)))
60716172# send information to child
6273set_spawning_popen(self)