bpo-33929: multiprocessing: fix handle leak on race condition (GH-7921) · python/cpython@8b1ebcd

@@ -18,6 +18,12 @@

1818

WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))

1919

WINSERVICE = 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):

3238

def __init__(self, process_obj):

3339

prep_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.

3747

rhandle, whandle = _winapi.CreatePipe(None, 0)

3848

wfd = msvcrt.open_osfhandle(whandle, 0)

3949

cmd = spawn.get_command_line(parent_pid=os.getpid(),

@@ -56,7 +66,8 @@ def __init__(self, process_obj):

5666

self.returncode = None

5767

self._handle = hp

5868

self.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

6273

set_spawning_popen(self)