Eryk Sun added the comment: > when I said "also with close_fds=True", I meant that I tried > WITHOUT overriding stdin, stdout, and stderr AND setting > close_fds=True, but it didn't work.
Console applications (e.g. python.exe) duplicate their standard handles into a child console process when the bInheritHandles argument of CreateProcess is false, i.e. when subprocess.Popen is called with the default close_fds=True. We know it's duplication instead of inheritance because the actual handle values change and also because it doesn't matter whether or not the standard handles are flagged as inheritable in the creating process. In the typical case this ensures that console processes have valid standard handles. However, if you make the standard handles non-inheritable in the parent and also inherit handles when creating the child, then the parent's standard handles will be neither inherited nor duplicated. The child will still inherit the standard handle *values* from the parent (i.e. copied from the parent's PEB ProcessParameters). These handle values will be invalid. Either the handle won't be defined, or it will reference an arbitrary, unrelated kernel object. > What worked was not overriding stdin/out/err and adding > > os.set_inheritable(0, False) > os.set_inheritable(1, False) > os.set_inheritable(2, False) > > before the call (no need to set close_fds) In this case cmd.exe gets duplicated standard handles, but you've flagged these handles as non-inheritable. When cmd.exe calls CreateProcess to execute waitfor.exe, it uses bInheritHandles=TRUE. Consequently, its non-inheritable standard handles are neither inherited by nor duplicated to waitfor.exe. Let's attach a debugger to the waitfor.exe process and examine the standard handle values in its PEB ProcessParameters: 0:003> ?? @$peb->ProcessParameters->StandardInput void * 0x00000000`00000008 0:003> !handle 8 Handle 8 Type Event 0:003> ?? @$peb->ProcessParameters->StandardOutput void * 0x00000000`0000000c 0:003> !handle c Handle c Type WaitCompletionPacket 0:003> ?? @$peb->ProcessParameters->StandardError void * 0x00000000`00000010 0:003> !handle 10 Handle 10 Type IoCompletion waitfor.exe doesn't care that its standard handle values reference non-File objects, i.e. an Event, a WaitCompletionPacket, and an IoCompletion port. However, what if by coincidence one of its standard handle values is actually a valid File handle that's inherited for some other reason? That would be a right mess. That's why I suggested overriding the standard handles to the NUL device. For example: import subprocess script = r''' import os import subprocess os.set_inheritable(0, False) os.set_inheritable(1, False) os.set_inheritable(2, False) cmdline = 'cmd.exe /s /c waitfor.exe signal /t 200' subprocess.run(cmdline, timeout=4, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) ''' args = ['python.exe', '-c', script] proc = subprocess.Popen(args, encoding='ansi', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc_out, proc_err = proc.communicate(timeout=20) print('proc_out:', proc_out) print('proc_err:', proc_err) ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue31447> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com