You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The following program fails to work on Windows. The program
terminates before the child finish. If another file handle than
STDOUT is used, then it works as expected. It also works as expected
on Linux.
non-Windows perl keeps process ids for piped opens in the PL_fdpid array, and for STD... handles openn_cleanup() carefully copies the process id from the original popenned fd to the STD... handle:
/* PL_fdpid isn't used on Windows, so avoid this useless work.
* XXX Probably the same for a lot of other places. */
{
Pid_tpid;
SV*sv;
sv=*av_fetch(PL_fdpid,fd,TRUE);
SvUPGRADE(sv, SVt_IV);
pid=SvIVX(sv);
SvIV_set(sv, 0);
sv=*av_fetch(PL_fdpid,savefd,TRUE);
SvUPGRADE(sv, SVt_IV);
SvIV_set(sv, pid);
}
#endif
Windows being Windows, it does it's own thing, using a separate array w32_fdpid (which is a macro for PL_sys_intern.fdpid) to store piped process ids, and openn_cleanup() doesn't try to handle that.
This means by the time we get to close(STDOUT) there's no process id associated with fd 1, so win32_pclose() fails to wait, and the parent process finishes execution without waiting for the child process to exit.
At this point I don't know why Win32 uses its own array here.
At this point I don't know why Win32 uses its own array here.
Hysterical Raisins.
status = spawnvp(mode, cmdname, (char * const *) argv);
-#ifndef __BORLANDC__
+#ifndef USE_RTL_WAIT
/* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
* while VC RTL returns pinfo.hProcess. For purposes of the custom
* implementation of win32_wait(), we assume the latter.
*/
@@ -2121,6 +2119,13 @@ Perl_init_os_extras()
MS CRT 6 thru MS UCRT, umm, I think MS has changed the CRT docs long ago, but ancient Perl claims their popen() (???) returns CloseHandle() integers, not GetCurrentProcessId() integers like Borland.
Current MSDN says retval of intptr_t spawnl(int Mode, const char *Filename, const char *ArgList, ...) depending on flags, is a CloseHandle() handle, not a NT PID.
my perl541.dll links to UCRT _spawnv and _execv only from perl541.dll's intptr_t win32_execv(const char *cmdname, const char *const *argv). perl541.dll's win32_execv() function is dead code inside perl541.dll. Function win32_execv() has no references from inside perl541.dll other than perl541.dll's PE export table.
Inside miniperl.exe, which has no export table, symbol win32_execv() is referenced by static int yyl_fake_eof(pTHX_ U32 fake_eof, bool bof, char *s), at location
decompiled, this isn't accurate b/c MSVC did so much variable and argument hoisting, folding, and inlining in this area, the asm code is unreadable, but it is approximately
but since the MS CRT/posix exec*() funcs are fatal calls, we dont care what the retval is. If it returns, we dont have a NT PID or NT HANDLE.
I cant find a fuzzy match spawn or popen sym import from UCRT to miniperl.exe . My guess, GUESS !!!, is modern WinPerl always calls CreateProcess() directly and therefore DIYs its own implementations of spawn/exec/open/waitpid/cwait/pwait instead of using buggy half baked MS CRT implementations of POSIX functions.
So WinPerl has no reason to attempt to separate proper NTnix/KERnix32 PIDs numbers from RefCounted NT Process handles for the last 10 or 20 years. WinPerl barely uses the MS CRT for anything but buffered STDIO and 0-based filenos nowadays.
Trivia, What is a Windows NT PID integer?
UM ClientId.UniqueProcess comes from KM UniqueProcessId. KM UniqueProcessId comes from ExCreateHandle(PspCidTable, &CidEntry);. So NT's PIDs numbers are offsets into a KM array of all live Process objects. For NT TIDs, s/Process/Thread/; So NT TIDs and PIDs use the same backend C class (lib/api) as "HANDLE"s from DuplicateHandle() and CloseHandle(). The TID/PID pool, and "HANDLE" pool, are 2 different object instances of the same "class". These 2 object instances of "class" obviously can't see each others private per object instance data (IE the array of void *s) and the numbers lives in different worlds, but both are super fast for the NT kernel to convert back and forth, and are super fast for NT Kernel to convert to a EPROCESS or KPROCESS struct ptr.
Activity
p5pRT commentedon Jun 19, 2001
From @gisle
The following program fails to work on Windows. The program
terminates before the child finish. If another file handle than
STDOUT is used, then it works as expected. It also works as expected
on Linux.
Perl Info
p5pRT commentedon May 25, 2016
From horst.reiterer@fabasoft.com
I can reproduce the issue with 5.10 and 5.22. The problem randomly breaks OpenSSL builds.
p5pRT commentedon May 25, 2016
From [Unknown Contact. See original ticket]
I can reproduce the issue with 5.10 and 5.22. The problem randomly breaks OpenSSL builds.
richardleach commentedon Oct 26, 2019
Still present in v5.30.0 on Win 10.
toddr commentedon Feb 4, 2020
@gisle FYI your case was moved here.
tonycoz commentedon Apr 23, 2025
non-Windows perl keeps process ids for piped opens in the
PL_fdpidarray, and forSTD...handles openn_cleanup() carefully copies the process id from the original popenned fd to theSTD...handle:perl5/doio.c
Lines 1092 to 1107 in 6c95af2
Windows being Windows, it does it's own thing, using a separate array
w32_fdpid(which is a macro forPL_sys_intern.fdpid) to store piped process ids, and openn_cleanup() doesn't try to handle that.This means by the time we get to
close(STDOUT)there's no process id associated with fd 1, so win32_pclose() fails to wait, and the parent process finishes execution without waiting for the child process to exit.At this point I don't know why Win32 uses its own array here.
Win32: eliminate the sys_intern fdpid aka w32_fdpid
3 remaining items
Win32: eliminate the sys_intern fdpid aka w32_fdpid
closepid.t: pclose tests that fail on Win32
Win32: eliminate the sys_intern fdpid aka w32_fdpid
Win32: eliminate the sys_intern fdpid aka w32_fdpid
closepid.t: pclose tests that fail on Win32
Win32: eliminate the sys_intern fdpid aka w32_fdpid
bulk88 commentedon Jun 19, 2025
Hysterical Raisins.
4b556e6
Borland Libc says a PID is a low 100s, low 1000s, random integer, obtained from MS public API
MS CRT 6 thru MS UCRT, umm, I think MS has changed the CRT docs long ago, but ancient Perl claims their
popen()(???) returnsCloseHandle()integers, notGetCurrentProcessId()integers like Borland.Current MSDN says retval of
intptr_t spawnl(int Mode, const char *Filename, const char *ArgList, ...)depending on flags, is aCloseHandle()handle, not a NT PID.https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/spawnl-wspawnl?view=msvc-170
more breadcrumbs: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/cwait?view=msvc-170
my
perl541.dlllinks to UCRT_spawnvand_execvonly fromperl541.dll'sintptr_t win32_execv(const char *cmdname, const char *const *argv).perl541.dll'swin32_execv()function is dead code insideperl541.dll. Functionwin32_execv()has no references from insideperl541.dllother thanperl541.dll's PE export table.Inside
miniperl.exe, which has no export table, symbolwin32_execv()is referenced bystatic int yyl_fake_eof(pTHX_ U32 fake_eof, bool bof, char *s), at locationdecompiled, this isn't accurate b/c MSVC did so much variable and argument hoisting, folding, and inlining in this area, the asm code is unreadable, but it is approximately
but since the MS CRT/posix
exec*()funcs are fatal calls, we dont care what the retval is. If it returns, we dont have a NT PID or NT HANDLE.I cant find a fuzzy match
spawnorpopensym import from UCRT tominiperl.exe. My guess, GUESS !!!, is modern WinPerl always callsCreateProcess()directly and therefore DIYs its own implementations ofspawn/exec/open/waitpid/cwait/pwaitinstead of using buggy half baked MS CRT implementations of POSIX functions.So WinPerl has no reason to attempt to separate proper NTnix/KERnix32 PIDs numbers from RefCounted NT Process handles for the last 10 or 20 years. WinPerl barely uses the MS CRT for anything but buffered STDIO and 0-based filenos nowadays.
Trivia, What is a Windows NT PID integer?
UM
ClientId.UniqueProcesscomes from KMUniqueProcessId. KMUniqueProcessIdcomes fromExCreateHandle(PspCidTable, &CidEntry);. So NT's PIDs numbers are offsets into a KM array of all live Process objects. For NT TIDs,s/Process/Thread/;So NT TIDs and PIDs use the same backend C class (lib/api) as "HANDLE"s fromDuplicateHandle()andCloseHandle(). The TID/PID pool, and "HANDLE" pool, are 2 different object instances of the same "class". These 2 object instances of "class" obviously can't see each others private per object instance data (IE the array of void *s) and the numbers lives in different worlds, but both are super fast for the NT kernel to convert back and forth, and are super fast for NT Kernel to convert to a EPROCESS or KPROCESS struct ptr.closepid.t: pclose tests that fail on Win32
Win32: eliminate the sys_intern fdpid aka w32_fdpid
Win32: eliminate the sys_intern fdpid aka w32_fdpid
closepid.t: pclose tests that fail on Win32
Win32: eliminate the sys_intern fdpid aka w32_fdpid
closepid.t: pclose tests that fail on Win32
Win32: eliminate the sys_intern fdpid aka w32_fdpid