Message302493
> 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) |
|
Date |
User |
Action |
Args |
2017-09-18 22:35:52 | eryksun | set | recipients:
+ eryksun, r.david.murray, martin.panter, Leonardo Francalanci |
2017-09-18 22:35:52 | eryksun | set | messageid: <1505774152.05.0.180373831426.issue31447@psf.upfronthosting.co.za> |
2017-09-18 22:35:52 | eryksun | link | issue31447 messages |
2017-09-18 22:35:51 | eryksun | create | |
|