|Subject:||Multi-argument system() invokes the shell under Win32|
|Date:||Sun, 08 Jul 2007 13:05:56 +1000|
|To:||perlbug [...] perl.org|
|From:||Paul Fenwick <pjf [...] perltraining.com.au>|
G'day wonderful maintainers, I've discovered that under Win32 systems the multi-argument version of system() will invoke the shell if it cannot locate the command. The following code demonstrates the problem: system("this_command_does_not_exist",1); printf("raw: %d ; apparent exit: %d\n",$?, $?>>8); A warning ('this_command_does_not_exist' is not recognised as an internal or external command) is printed to STDERR as the shell fails to locate the command, and $? is set to a value of 1 << 8 (ie, 256) which corresponds to the shell's exit value of 1, meaning command not found. As far as I can tell, whenever the win32 port of Perl fails to start a command, it tries it using the shell, just in case that will succeed. This happens regardless of the form of system() used. There are two issues this presents: 1) It's very difficult to tell the difference between a call to system() that resulted in a command that failed to start, and a command that started successfully but merely returned an exit value of 1. 2) The shell may be invoked even though the multi-argument form was used. This is not consistent with the documentation in 'perldoc -f system' and 'perldoc -f exec', which advertises this as a way to avoid the shell. Having the multi-argument form of system always avoid the shell overcomes these difficulties, and makes it consistent with the Unix port. This probably involves modification of the win32/win32.c functions Perl_do_aspawn() and do_spawn2(), but it's been a long time since I've had to dig that far into Perl's guts. Of course, our risk here is that if anyone's actually been relying upon this behaviour then they're going to get quite a surprise. I'm not a Windows guru, and can't easily gauge how much code may break from such a change. I believe our other option is to document this in perlfunc, perlport and perlwin32 appropriately. I'm happy to do the legwork here (be it documentation or code), but I'm eager for advice as to what our best solution may be. I'll be independently upgrading IPC::System::Simple on the CPAN in the next few days to provide an interface to system() that's consistent with the Unix implementation (always skipping the shell on multi-arg calls), as well as exposing the full 16-bit return value. Cheerio, Paul Obligatory perl -V data follows. Summary of my perl5 (revision 5 version 8 subversion 8) configuration: Platform: osname=MSWin32, osvers=5.0, archname=MSWin32-x86-multi-thread uname='' config_args='undef' hint=recommended, useposix=true, d_sigaction=undef usethreads=define use5005threads=undef useithreads=define usemultiplicity=define useperlio=define d_sfio=undef uselargefiles=define usesocks=undef use64bitint=undef use64bitall=undef uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cl', ccflags ='-nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT -DNO_HASH_SEED -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX', optimize='-MD -Zi -DNDEBUG -O1', cppflags='-DWIN32' ccversion='12.00.8804', gccversion='', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=10 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='link', ldflags ='-nologo -nodefaultlib -debug -opt:ref,icf -libpath:"C:\Perl\lib\CORE" -machine:x86' libpth=\lib libs= oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib perllibs= oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib libc=msvcrt.lib, so=dll, useshrplib=yes, libperl=perl58.lib gnulibc_version='' Dynamic Linking: dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' ' cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -debug -opt:ref,icf -libpath:"C:\Perl\lib\CORE" -machine:x86' Characteristics of this binary (from libperl): Compile-time options: MULTIPLICITY PERL_IMPLICIT_CONTEXT PERL_IMPLICIT_SYS PERL_MALLOC_WRAP PL_OP_SLAB_ALLOC USE_ITHREADS USE_LARGE_FILES USE_PERLIO USE_SITECUSTOMIZE Locally applied patches: ActivePerl Build 817  Iin_load_module moved for compatibility with build 806 PerlEx support in CGI::Carp Less verbose ExtUtils::Install and Pod::Find Patch for CAN-2005-0448 from Debian with modifications Partly reverted 24733 to preserve binary compatibilty 27528 win32_pclose() error exit doesn't unlock mutex 27527 win32_async_check() can loop indefinitely 27515 ignore directories when searching @INC 27359 Fix -d:Foo=bar syntax 27210 Fix quote typo in c2ph 27203 Allow compiling swigged C++ code 27200 Make stat() on Windows handle trailing slashes correctly 27194 Get perl_fini() running on HP-UX again 27133 Initialise lastparen in the regexp structure 27034 Avoid "Prototype mismatch" warnings with autouse 26970 Make Passive mode the default for Net::FTP 26921 Avoid getprotobyname/number calls in IO::Socket::INET 26897,26903 Make common IPPROTO_* constants always available 26670 Make '-s' on the shebang line parse -foo=bar switches 26379 Fix alarm() for Windows 2003 26087 Storable 0.1 compatibility 25861 IO::File performace issue 25084 long groups entry could cause memory exhaustion 24699 ICMP_UNREACHABLE handling in Net::Ping Built under MSWin32 Compiled at Mar 20 2006 17:54:25 @INC: C:/Perl/lib C:/Perl/site/lib .