develooper Front page | perl.perl5.porters | Postings from May 2015

[perl #121283] system() on Win32 tries to launch bogus paths+bad cmd parsing

From:
Steve Hay via RT
Date:
May 9, 2015 17:46
Subject:
[perl #121283] system() on Win32 tries to launch bogus paths+bad cmd parsing
Message ID:
rt-4.0.18-15577-1431193595-374.121283-14-0@perl.org
Sorry if this has already been mentioned. I had a skim read of the above and didn't see it, so I thought I'd record it here for future reference:

The cmd.exe that unexpectedly gets launched to launch the perl.exe (instead of perl.exe getting launched directly) sometimes doesn't happen when using system("$perl ...") rather than system(1, "$perl ..."). (The discussion so far has been regarding the latter form, specifically a case in t/test.pl's watchdog().)

The example I've just stumbled across is that this:

perl -le "system(1, qq[$^X -e sleep(10)])"

launches a cmd.exe which launches a perl.exe which sleeps for 10 seconds, which can be clearly seen in the tree view of Process Explorer: the cmd.exe->perl.exe pair are separated from the cmd.exe in which I ran the above command because the system(1, ...) form doesn't wait for the command to complete so the perl.exe than I ran from my cmd.exe immediately exits, leaving just the cmd.exe->perl.exe that it launched, now separated from my cmd.exe. You can see this more clearly by running:

perl -le "system(1, qq[$^X -e sleep(10)]); sleep(5)"

in which the perl.exe that I ran from my cmd.exe sticks around for 5 seconds with the cmd.exe->perl.exe underneath it before exiting.

Whereas this:

perl -le "system(qq[$^X -e sleep(10)])"

does NOT launch the unexpected cmd.exe, which can again be clearly seen in Process Explorer: the perl.exe than I ran from my cmd.exe only has another perl.exe underneath it.

I don't know if that's a useful observation or not; I just thought I'd mention it since it surprised me.

Another thing I noticed is that shortly after this ticket appeared, there was another discussion on p5p (see the thread beginning here: http://www.nntp.perl.org/group/perl.perl5.porters/2014/04/msg214390.html) which wound up in commit http://perl5.git.perl.org/perl.git/commit/94d4006a6d, which noted that, "On Windows, only the system PROGRAM LIST syntax will reliably avoid using the shell; system LIST, even with more than one element, will fall back to the shell if the first spawn fails."

That suggests to me that changing

perl -le "system(1, qq[$^X -e sleep(10)])"

to

perl -le "system({$^X} 1, qq[$^X -e sleep(10)])"

should workaround the problem.

Indeed, it does, but seems to reveal some other new problem?! -- the perl.exe that I ran from my cmd.exe does indeed now run the other perl.exe directly, without an intermediate cmd.exe, but the second perl.exe (with the -e sleep(10) arguments) hangs indefinitely instead of exiting after 10 seconds.

I wondered if the indirect object part was causing some confusion with the special leading "1", but this:

perl -le "system({$^X} qq[$^X -e sleep(10)])"

(which works around the unexpected cmd.exe problem itself by omitting that leading "1", of course, as noted earlier) also still hangs indefinitely.

In this case, the system LIST form avoids the unwanted cmd.exe anyway, i.e. this behaves as expected:

perl -le "system($^X, '-e', 'sleep(10)')"

and with this multi-element LIST form, the indirect object syntax no longer hangs indefinitely either, i.e. this also behaves as expected:

perl -le "system({$^X} $^X, '-e', 'sleep(10)')"

In fact, both of these forms also work as expected with the leading "1" too, i.e.:

perl -le "system(1, $^X, '-e', 'sleep(10)')"

perl -le "system({$^X} 1, $^X, '-e', 'sleep(10)')"

So to summarize all this:

perl -le "system(1, qq[$^X -e sleep(10)])"
uses cmd.exe

perl -le "system(qq[$^X -e sleep(10)])"
ok

perl -le "system({$^X} 1, qq[$^X -e sleep(10)])"
no cmd.exe but hangs

perl -le "system({$^X} qq[$^X -e sleep(10)])"
no cmd.exe but hangs

perl -le "system(1, $^X, '-e', 'sleep(10)')"
ok

perl -le "system($^X, '-e', 'sleep(10)')"
ok

perl -le "system({$^X} 1, $^X, '-e', 'sleep(10)')"
ok

perl -le "system({$^X} $^X, '-e', 'sleep(10)')"
ok




nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About