make exec keep its argument list more reliably
authorZefram <zefram@fysh.org>
Wed, 6 Dec 2017 21:27:15 +0000 (21:27 +0000)
committerZefram <zefram@fysh.org>
Thu, 14 Dec 2017 22:48:30 +0000 (22:48 +0000)
Bits of exec code were putting the constructed commands into globals
PL_Argv and PL_Cmd, which could then be clobbered by reentrancy.
These are only global in order to manage their freeing, but that's
better managed by using the scope stack.  So replace them with automatic
variables, with ENTER/SAVEFREEPV/LEAVE to free the memory.  Also copy
the strings acquired from SVs, to avoid magic clobbering the buffers of
SVs already read.  Fixes [perl #129888].

14 files changed:
amigaos4/amigaio.c
cygwin/cygwin.c
djgpp/djgpp.c
doio.c
embed.fnc
embed.h
embedvar.h
intrpvar.h
os2/os2.c
pp_sys.c
proto.h
sv.c
util.c
vms/vms.c

index b471220..edc237a 100644 (file)
@@ -646,7 +646,7 @@ static void S_exec_failed(pTHX_ const char *cmd, int fd, int do_report)
 static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
 {
        dVAR;
-       const char **a;
+       const char **argv, **a;
        char *s;
        char *buf;
        char *cmd;
@@ -656,7 +656,9 @@ static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
 
        PERL_ARGS_ASSERT_DO_EXEC3;
 
+       ENTER;
        Newx(buf, cmdlen, char);
+       SAVEFREEPV(buf);
        cmd = buf;
        memcpy(cmd, incmd, cmdlen);
 
@@ -709,15 +711,16 @@ doshell:
                        PERL_FPU_POST_EXEC
                        S_exec_failed(aTHX_ PL_sh_path, fd, do_report);
                        amigaos_post_exec(fd, do_report);
-                       Safefree(buf);
-                       return result;
+                       goto leave;
                }
        }
 
-       Newx(PL_Argv, (s - cmd) / 2 + 2, const char *);
-       PL_Cmd = savepvn(cmd, s - cmd);
-       a = PL_Argv;
-       for (s = PL_Cmd; *s;)
+       Newx(argv, (s - cmd) / 2 + 2, const char *);
+       SAVEFREEPV(argv);
+       cmd = savepvn(cmd, s - cmd);
+       SAVEFREEPV(cmd);
+       a = argv;
+       for (s = cmd; *s;)
        {
                while (isSPACE(*s))
                        s++;
@@ -729,22 +732,18 @@ doshell:
                        *s++ = '\0';
        }
        *a = NULL;
-       if (PL_Argv[0])
+       if (argv[0])
        {
                PERL_FPU_PRE_EXEC
-               result = myexecvp(FALSE, PL_Argv[0], EXEC_ARGV_CAST(PL_Argv));
+               result = myexecvp(FALSE, argv[0], EXEC_ARGV_CAST(argv));
                PERL_FPU_POST_EXEC
-               if (errno == ENOEXEC)
-               {
-                       /* for system V NIH syndrome */
-                       do_execfree();
+               if (errno == ENOEXEC) /* for system V NIH syndrome */
                        goto doshell;
-               }
-               S_exec_failed(aTHX_ PL_Argv[0], fd, do_report);
+               S_exec_failed(aTHX_ argv[0], fd, do_report);
                amigaos_post_exec(fd, do_report);
        }
-       do_execfree();
-       Safefree(buf);
+leave:
+       LEAVE;
        return result;
 }
 
@@ -754,42 +753,47 @@ I32 S_do_amigaos_aexec5(
        dVAR;
        I32 result = -1;
        PERL_ARGS_ASSERT_DO_AEXEC5;
+       ENTER;
        if (sp > mark)
        {
-               const char **a;
+               const char **argv, **a;
                const char *tmps = NULL;
-               Newx(PL_Argv, sp - mark + 1, const char *);
-               a = PL_Argv;
+               Newx(argv, sp - mark + 1, const char *);
+               SAVEFREEPV(argv);
+               a = argv;
 
                while (++mark <= sp)
                {
-                       if (*mark)
-                               *a++ = SvPV_nolen_const(*mark);
-                       else
+                       if (*mark) {
+                               char *arg = savepv(SvPV_nolen_const(*mark));
+                               SAVEFREEPV(arg);
+                               *a++ = arg;
+                       } else
                                *a++ = "";
                }
                *a = NULL;
-               if (really)
-                       tmps = SvPV_nolen_const(really);
-               if ((!really && *PL_Argv[0] != '/') ||
+               if (really) {
+                       tmps = savepv(SvPV_nolen_const(really));
+                       SAVEFREEPV(tmps);
+               }
+               if ((!really && *argv[0] != '/') ||
                        (really && *tmps != '/')) /* will execvp use PATH? */
                        TAINT_ENV(); /* testing IFS here is overkill, probably
                                         */
                PERL_FPU_PRE_EXEC
                if (really && *tmps)
                {
-                       result = myexecvp(FALSE, tmps, EXEC_ARGV_CAST(PL_Argv));
+                       result = myexecvp(FALSE, tmps, EXEC_ARGV_CAST(argv));
                }
                else
                {
-                       result = myexecvp(FALSE, PL_Argv[0],
-                                         EXEC_ARGV_CAST(PL_Argv));
+                       result = myexecvp(FALSE, argv[0], EXEC_ARGV_CAST(argv));
                }
                PERL_FPU_POST_EXEC
-               S_exec_failed(aTHX_(really ? tmps : PL_Argv[0]), fd, do_report);
+               S_exec_failed(aTHX_(really ? tmps : argv[0]), fd, do_report);
        }
        amigaos_post_exec(fd, do_report);
-       do_execfree();
+       LEAVE;
        return result;
 }
 
index a234825..fae90af 100644 (file)
@@ -90,11 +90,13 @@ int
 do_spawn (char *cmd)
 {
     dTHX;
-    char const **a;
+    char const **argv, **a;
     char *s;
     char const *metachars = "$&*(){}[]'\";\\?>|<~`\n";
     const char *command[4];
+    int result;
 
+    ENTER;
     while (*cmd && isSPACE(*cmd))
        cmd++;
 
@@ -127,13 +129,16 @@ do_spawn (char *cmd)
            command[2] = cmd;
            command[3] = NULL;
 
-           return do_spawnvp("sh",command);
+           result = do_spawnvp("sh",command);
+           goto leave;
        }
 
-    Newx (PL_Argv, (s-cmd)/2+2, const char*);
-    PL_Cmd=savepvn (cmd,s-cmd);
-    a=PL_Argv;
-    for (s=PL_Cmd; *s;) {
+    Newx (argv, (s-cmd)/2+2, const char*);
+    SAVEFREEPV(argv);
+    cmd=savepvn (cmd,s-cmd);
+    SAVEFREEPV(cmd);
+    a=argv;
+    for (s=cmd; *s;) {
        while (*s && isSPACE (*s)) s++;
        if (*s)
            *(a++)=s;
@@ -142,10 +147,13 @@ do_spawn (char *cmd)
            *s++='\0';
     }
     *a = (char*)NULL;
-    if (!PL_Argv[0])
-        return -1;
-
-    return do_spawnvp(PL_Argv[0],(const char * const *)PL_Argv);
+    if (!argv[0])
+        result = -1;
+    else
+       result = do_spawnvp(argv[0],(const char * const *)argv);
+leave:
+    LEAVE;
+    return result;
 }
 
 #if (CYGWIN_VERSION_API_MINOR >= 181)
index d1c09aa..24d12f2 100644 (file)
@@ -150,9 +150,10 @@ do_aspawn (pTHX_ SV *really,SV **mark,SV **sp)
 int
 do_spawn2 (pTHX_ char *cmd,int execf)
 {
-    char **a,*s,*shell,*metachars;
-    int  rc,unixysh;
+    char **argv,**a,*s,*shell,*metachars;
+    int  rc,unixysh,result;
 
+    ENTER;
     if ((shell=getenv("SHELL"))==NULL && (shell=getenv("COMSPEC"))==NULL)
        shell="c:\\command.com" EXTRA;
 
@@ -189,14 +190,18 @@ do_spawn2 (pTHX_ char *cmd,int execf)
            }
 doshell:
            if (execf==EXECF_EXEC)
-                return convretcode (execl (shell,shell,unixysh ? "-c" : "/c",cmd,NULL),cmd,execf);
-            return convretcode (system (cmd),cmd,execf);
+                result = convretcode (execl (shell,shell,unixysh ? "-c" : "/c",cmd,NULL),cmd,execf);
+           else
+               result = convretcode (system (cmd),cmd,execf);
+           goto leave;
        }
 
-    Newx (PL_Argv,(s-cmd)/2+2,char*);
-    PL_Cmd=savepvn (cmd,s-cmd);
-    a=PL_Argv;
-    for (s=PL_Cmd; *s;) {
+    Newx (argv,(s-cmd)/2+2,char*);
+    SAVEFREEPV(argv);
+    cmd=savepvn (cmd,s-cmd);
+    SAVEFREEPV(cmd);
+    a=argv;
+    for (s=cmd; *s;) {
        while (*s && isSPACE (*s)) s++;
        if (*s)
            *(a++)=s;
@@ -205,14 +210,19 @@ doshell:
            *s++='\0';
     }
     *a=NULL;
-    if (!PL_Argv[0])
-        return -1;
+    if (!argv[0]) {
+        result = -1;
+       goto leave;
+    }
 
     if (execf==EXECF_EXEC)
-        rc=execvp (PL_Argv[0],PL_Argv);
+        rc=execvp (argv[0],argv);
     else
-        rc=spawnvp (P_WAIT,PL_Argv[0],PL_Argv);
-    return convretcode (rc,PL_Argv[0],execf);
+        rc=spawnvp (P_WAIT,argv[0],argv);
+    result = convretcode (rc,argv[0],execf);
+leave:
+    LEAVE;
+    return result;
 }
 
 int
diff --git a/doio.c b/doio.c
index 9b713e1..c98a5f5 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1992,56 +1992,53 @@ Perl_do_aexec5(pTHX_ SV *really, SV **mark, SV **sp,
     Perl_croak(aTHX_ "exec? I'm not *that* kind of operating system");
 #else
     assert(sp >= mark);
+    ENTER;
     {
-       const char **a;
+       const char **argv, **a;
        const char *tmps = NULL;
-       Newx(PL_Argv, sp - mark + 1, const char*);
-       a = PL_Argv;
+       Newx(argv, sp - mark + 1, const char*);
+       SAVEFREEPV(argv);
+       a = argv;
 
        while (++mark <= sp) {
-           if (*mark)
-               *a++ = SvPV_nolen_const(*mark);
-           else
+           if (*mark) {
+               char *arg = savepv(SvPV_nolen_const(*mark));
+               SAVEFREEPV(arg);
+               *a++ = arg;
+           } else
                *a++ = "";
        }
        *a = NULL;
-       if (really)
-           tmps = SvPV_nolen_const(really);
-        if ((!really && PL_Argv[0] && *PL_Argv[0] != '/') ||
+       if (really) {
+           tmps = savepv(SvPV_nolen_const(really));
+           SAVEFREEPV(tmps);
+       }
+        if ((!really && argv[0] && *argv[0] != '/') ||
            (really && *tmps != '/'))           /* will execvp use PATH? */
            TAINT_ENV();                /* testing IFS here is overkill, probably */
        PERL_FPU_PRE_EXEC
        if (really && *tmps) {
-            PerlProc_execvp(tmps,EXEC_ARGV_CAST(PL_Argv));
-        } else if (PL_Argv[0]) {
-            PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
+            PerlProc_execvp(tmps,EXEC_ARGV_CAST(argv));
+        } else if (argv[0]) {
+            PerlProc_execvp(argv[0],EXEC_ARGV_CAST(argv));
         } else {
             SETERRNO(ENOENT,RMS_FNF);
         }
        PERL_FPU_POST_EXEC
-        S_exec_failed(aTHX_ (really ? tmps : PL_Argv[0] ? PL_Argv[0] : ""), fd, do_report);
+        S_exec_failed(aTHX_ (really ? tmps : argv[0] ? argv[0] : ""), fd, do_report);
     }
-    do_execfree();
+    LEAVE;
 #endif
     return FALSE;
 }
 
-void
-Perl_do_execfree(pTHX)
-{
-    Safefree(PL_Argv);
-    PL_Argv = NULL;
-    Safefree(PL_Cmd);
-    PL_Cmd = NULL;
-}
-
 #ifdef PERL_DEFAULT_DO_EXEC3_IMPLEMENTATION
 
 bool
 Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
 {
     dVAR;
-    const char **a;
+    const char **argv, **a;
     char *s;
     char *buf;
     char *cmd;
@@ -2050,7 +2047,9 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
 
     PERL_ARGS_ASSERT_DO_EXEC3;
 
+    ENTER;
     Newx(buf, cmdlen, char);
+    SAVEFREEPV(buf);
     cmd = buf;
     memcpy(cmd, incmd, cmdlen);
 
@@ -2086,8 +2085,7 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
                  PERL_FPU_POST_EXEC
                  *s = '\'';
                  S_exec_failed(aTHX_ PL_cshname, fd, do_report);
-                 Safefree(buf);
-                 return FALSE;
+                 goto leave;
              }
          }
        }
@@ -2134,15 +2132,16 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
             PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL);
            PERL_FPU_POST_EXEC
            S_exec_failed(aTHX_ PL_sh_path, fd, do_report);
-           Safefree(buf);
-           return FALSE;
+           goto leave;
        }
     }
 
-    Newx(PL_Argv, (s - cmd) / 2 + 2, const char*);
-    PL_Cmd = savepvn(cmd, s-cmd);
-    a = PL_Argv;
-    for (s = PL_Cmd; *s;) {
+    Newx(argv, (s - cmd) / 2 + 2, const char*);
+    SAVEFREEPV(argv);
+    cmd = savepvn(cmd, s-cmd);
+    SAVEFREEPV(cmd);
+    a = argv;
+    for (s = cmd; *s;) {
        while (isSPACE(*s))
            s++;
        if (*s)
@@ -2153,18 +2152,16 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
            *s++ = '\0';
     }
     *a = NULL;
-    if (PL_Argv[0]) {
+    if (argv[0]) {
        PERL_FPU_PRE_EXEC
-        PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
+        PerlProc_execvp(argv[0],EXEC_ARGV_CAST(argv));
        PERL_FPU_POST_EXEC
-       if (errno == ENOEXEC) {         /* for system V NIH syndrome */
-           do_execfree();
+       if (errno == ENOEXEC)           /* for system V NIH syndrome */
            goto doshell;
-       }
-       S_exec_failed(aTHX_ PL_Argv[0], fd, do_report);
+       S_exec_failed(aTHX_ argv[0], fd, do_report);
     }
-    do_execfree();
-    Safefree(buf);
+leave:
+    LEAVE;
     return FALSE;
 }
 
index ad4df86..3387026 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -437,7 +437,6 @@ Ap  |int    |do_spawn_nowait|NN char* cmd
 #if !defined(WIN32)
 p      |bool|do_exec3  |NN const char *incmd|int fd|int do_report
 #endif
-p      |void   |do_execfree
 #if defined(PERL_IN_DOIO_C)
 s      |void   |exec_failed    |NN const char *cmd|int fd|int do_report
 #endif
diff --git a/embed.h b/embed.h
index fb4832d..a410a35 100644 (file)
--- a/embed.h
+++ b/embed.h
 #define do_aexec5(a,b,c,d,e)   Perl_do_aexec5(aTHX_ a,b,c,d,e)
 #define do_dump_pad(a,b,c,d)   Perl_do_dump_pad(aTHX_ a,b,c,d)
 #define do_eof(a)              Perl_do_eof(aTHX_ a)
-#define do_execfree()          Perl_do_execfree(aTHX)
 #define do_ncmp(a,b)           Perl_do_ncmp(aTHX_ a,b)
 #define do_open6(a,b,c,d,e,f)  Perl_do_open6(aTHX_ a,b,c,d,e,f)
 #define do_open_raw(a,b,c,d,e,f)       Perl_do_open_raw(aTHX_ a,b,c,d,e,f)
index 1a146c4..635a01a 100644 (file)
@@ -41,9 +41,7 @@
 #  endif
 
 #define PL_AboveLatin1         (vTHX->IAboveLatin1)
-#define PL_Argv                        (vTHX->IArgv)
 #define PL_Assigned_invlist    (vTHX->IAssigned_invlist)
-#define PL_Cmd                 (vTHX->ICmd)
 #define PL_DBcontrol           (vTHX->IDBcontrol)
 #define PL_DBcv                        (vTHX->IDBcv)
 #define PL_DBgv                        (vTHX->IDBgv)
index d88628a..006880a 100644 (file)
@@ -456,8 +456,6 @@ PERLVARI(I, curcopdb,       COP *,  NULL)
 PERLVAR(I, filemode,   int)            /* so nextargv() can preserve mode */
 PERLVAR(I, lastfd,     int)            /* what to preserve mode on */
 PERLVAR(I, oldname,    char *)         /* what to preserve mode on */
-PERLVAR(I, Argv,       const char **)  /* stuff to free from do_aexec, vfork safe */
-PERLVAR(I, Cmd,                char *)         /* stuff to free from do_aexec, vfork safe */
 /* Elements in this array have ';' appended and are injected as a single line
    into the tokeniser. You can't put any (literal) newlines into any program
    you stuff in into this array, as the point where it's injected is expecting
index 66f387b..54c7ef1 100644 (file)
--- a/os2/os2.c
+++ b/os2/os2.c
@@ -970,7 +970,6 @@ file_type(char *path)
 }
 
 /* Spawn/exec a program, revert to shell if needed. */
-/* global PL_Argv[] contains arguments. */
 
 extern ULONG _emx_exception (  EXCEPTIONREPORTRECORD *,
                                EXCEPTIONREGISTRATIONRECORD *,
@@ -978,7 +977,7 @@ extern ULONG _emx_exception (       EXCEPTIONREPORTRECORD *,
                                 void *);
 
 int
-do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
+do_spawn_ve(pTHX_ SV *really, const char **argv, U32 flag, U32 execf, char *inicmd, U32 addflag)
 {
        int trueflag = flag;
        int rc, pass = 1;
@@ -997,16 +996,21 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
        
        if (flag == P_WAIT)
                flag = P_NOWAIT;
-       if (really && !*(real_name = SvPV(really, n_a)))
-           really = NULL;
+       if (really) {
+           real_name = SvPV(really, n_a);
+           real_name = savepv(real_name);
+           SAVEFREEPV(real_name);
+           if (!*real_name)
+               really = NULL;
+       }
 
       retry:
-       if (strEQ(PL_Argv[0],"/bin/sh")) 
-           PL_Argv[0] = PL_sh_path;
+       if (strEQ(argv[0],"/bin/sh")) 
+           argv[0] = PL_sh_path;
 
        /* We should check PERL_SH* and PERLLIB_* as well? */
        if (!really || pass >= 2)
-           real_name = PL_Argv[0];
+           real_name = argv[0];
        if (real_name[0] != '/' && real_name[0] != '\\'
            && !(real_name[0] && real_name[1] == ':' 
                 && (real_name[2] == '/' || real_name[2] != '\\'))
@@ -1098,30 +1102,30 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
        }
 
 #if 0
-       rc = result(aTHX_ trueflag, spawnvp(flag,real_name,PL_Argv));
+       rc = result(aTHX_ trueflag, spawnvp(flag,real_name,argv));
 #else
        if (execf == EXECF_TRUEEXEC)
-           rc = execvp(real_name,PL_Argv);
+           rc = execvp(real_name,argv);
        else if (execf == EXECF_EXEC)
-           rc = spawnvp(trueflag | P_OVERLAY,real_name,PL_Argv);
+           rc = spawnvp(trueflag | P_OVERLAY,real_name,argv);
        else if (execf == EXECF_SPAWN_NOWAIT)
-           rc = spawnvp(flag,real_name,PL_Argv);
+           rc = spawnvp(flag,real_name,argv);
         else if (execf == EXECF_SYNC)
-           rc = spawnvp(trueflag,real_name,PL_Argv);
+           rc = spawnvp(trueflag,real_name,argv);
         else                           /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
            rc = result(aTHX_ trueflag, 
-                       spawnvp(flag,real_name,PL_Argv));
+                       spawnvp(flag,real_name,argv));
 #endif 
        if (rc < 0 && pass == 1) {
              do_script:
-         if (real_name == PL_Argv[0]) {
+         if (real_name == argv[0]) {
            int err = errno;
 
            if (err == ENOENT || err == ENOEXEC) {
                /* No such file, or is a script. */
                /* Try adding script extensions to the file name, and
                   search on PATH. */
-               char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
+               char *scr = find_script(argv[0], TRUE, NULL, 0);
 
                if (scr) {
                    char *s = 0, *s1;
@@ -1132,7 +1136,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
                    scr = SvPV(scrsv, n_a); /* free()ed later */
 
                    file = PerlIO_open(scr, "r");
-                   PL_Argv[0] = scr;
+                   argv[0] = scr;
                    if (!file)
                        goto panic_file;
 
@@ -1148,7 +1152,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
                           does not append ".exe", so we could have
                           reached this place). */
                        sv_catpv(scrsv, ".exe");
-                       PL_Argv[0] = scr = SvPV(scrsv, n_a);    /* Reload */
+                       argv[0] = scr = SvPV(scrsv, n_a);       /* Reload */
                         if (PerlLIO_stat(scr,&statbuf) >= 0
                             && !S_ISDIR(statbuf.st_mode)) {    /* Found */
                                real_name = scr;
@@ -1214,7 +1218,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
                    /* Can jump from far, buf/file invalid if force_shell: */
                  doshell_args:
                    {
-                       char **a = PL_Argv;
+                       char **a = argv;
                        const char *exec_args[2];
 
                        if (force_shell 
@@ -1240,7 +1244,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
                                    }
                                }
                                if (!inicmd) {
-                                   s = PL_Argv[0];
+                                   s = argv[0];
                                    while (*s) { 
                                        /* Dosish shells will choke on slashes
                                           in paths, fortunately, this is
@@ -1265,29 +1269,29 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
                                /* Use the original cmd line */
                                /* XXXX This is good only until we refuse
                                        quoted arguments... */
-                               PL_Argv[0] = inicmd;
-                               PL_Argv[1] = NULL;
+                               argv[0] = inicmd;
+                               argv[1] = NULL;
                            }
                        } else if (!buf[0] && inicmd) { /* No file */
                            /* Start with the original cmdline. */
                            /* XXXX This is good only until we refuse
                                    quoted arguments... */
 
-                           PL_Argv[0] = inicmd;
-                           PL_Argv[1] = NULL;
+                           argv[0] = inicmd;
+                           argv[1] = NULL;
                            nargs = 2;  /* shell -c */
                        } 
 
                        while (a[1])            /* Get to the end */
                            a++;
                        a++;                    /* Copy finil NULL too */
-                       while (a >= PL_Argv) {
-                           *(a + nargs) = *a;  /* PL_Argv was preallocated to be
+                       while (a >= argv) {
+                           *(a + nargs) = *a;  /* argv was preallocated to be
                                                   long enough. */
                            a--;
                        }
                        while (--nargs >= 0) /* XXXX Discard const... */
-                           PL_Argv[nargs] = (char*)argsp[nargs];
+                           argv[nargs] = (char*)argsp[nargs];
                        /* Enable pathless exec if #! (as pdksh). */
                        pass = (buf[0] == '#' ? 2 : 3);
                        goto retry;
@@ -1301,23 +1305,23 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
                    Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s script `%s' with ARGV[0] being `%s'", 
                         ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC) 
                          ? "spawn" : "exec"),
-                        real_name, PL_Argv[0]);
+                        real_name, argv[0]);
                goto warned;
          } else if (errno == ENOENT) { /* Cannot transfer `real_name' via shell. */
                if (rc < 0 && ckWARN(WARN_EXEC))
                    Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s `%s' with ARGV[0] being `%s' (looking for executables only, not found)", 
                         ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC) 
                          ? "spawn" : "exec"),
-                        real_name, PL_Argv[0]);
+                        real_name, argv[0]);
                goto warned;
          }
        } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
-           char *no_dir = strrchr(PL_Argv[0], '/');
+           char *no_dir = strrchr(argv[0], '/');
 
            /* Do as pdksh port does: if not found with /, try without
               path. */
            if (no_dir) {
-               PL_Argv[0] = no_dir + 1;
+               argv[0] = no_dir + 1;
                pass++;
                goto retry;
            }
@@ -1346,11 +1350,12 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
 int
 do_spawn3(pTHX_ char *cmd, int execf, int flag)
 {
-    char **a;
+    char **argv, **a;
     char *s;
     char *shell, *copt, *news = NULL;
     int rc, seenspace = 0, mergestderr = 0;
 
+    ENTER;
 #ifdef TRYSHELL
     if ((shell = getenv("EMXSHELL")) != NULL)
        copt = "-c";
@@ -1441,17 +1446,19 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag)
            }
            if (news)
                Safefree(news);
-           return rc;
+           goto leave;
        } else if (*s == ' ' || *s == '\t') {
            seenspace = 1;
        }
     }
 
     /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
-    Newx(PL_Argv, (s - cmd + 11) / 2, char*);
-    PL_Cmd = savepvn(cmd, s-cmd);
-    a = PL_Argv;
-    for (s = PL_Cmd; *s;) {
+    Newx(argv, (s - cmd + 11) / 2, char*);
+    SAVEFREEPV(argv);
+    cmd = savepvn(cmd, s-cmd);
+    SAVEFREEPV(cmd);
+    a = argv;
+    for (s = cmd; *s;) {
        while (*s && isSPACE(*s)) s++;
        if (*s)
            *(a++) = s;
@@ -1460,13 +1467,14 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag)
            *s++ = '\0';
     }
     *a = NULL;
-    if (PL_Argv[0])
-       rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
+    if (argv[0])
+       rc = do_spawn_ve(aTHX_ NULL, argv, flag, execf, cmd, mergestderr);
     else
        rc = -1;
     if (news)
        Safefree(news);
-    do_execfree();
+leave:
+    LEAVE;
     return rc;
 }
 
@@ -1480,14 +1488,16 @@ os2_aspawn_4(pTHX_ SV *really, SV **args, I32 cnt, int execing)
 {
     SV **argp = (SV **)args;
     SV **last = argp + cnt;
-    char **a;
+    char **argv, **a;
     int rc;
     int flag = P_WAIT, flag_set = 0;
     STRLEN n_a;
 
+    ENTER;
     if (cnt) {
-       Newx(PL_Argv, cnt + 3, char*); /* 3 extra to expand #! */
-       a = PL_Argv;
+       Newx(argv, cnt + 3, char*); /* 3 extra to expand #! */
+       SAVEFREEPV(argv);
+       a = argv;
 
        if (cnt > 1 && SvNIOKp(*argp) && !SvPOKp(*argp)) {
            flag = SvIVx(*argp);
@@ -1496,24 +1506,27 @@ os2_aspawn_4(pTHX_ SV *really, SV **args, I32 cnt, int execing)
            --argp;
 
        while (++argp < last) {
-           if (*argp)
-               *a++ = SvPVx(*argp, n_a);
-           else
+           if (*argp) {
+               char *arg = SvPVx(*argp, n_a);
+               arg = savepv(arg);
+               SAVEFREEPV(arg);
+               *a++ = arg;
+           } else
                *a++ = "";
        }
        *a = NULL;
 
-       if ( flag_set && (a == PL_Argv + 1)
+       if ( flag_set && (a == argv + 1)
             && !really && execing == ASPAWN_WAIT ) {           /* One arg? */
            rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
        } else {
            const int execf[3] = {EXECF_SPAWN, EXECF_EXEC, EXECF_SPAWN_NOWAIT};
            
-           rc = do_spawn_ve(aTHX_ really, flag, execf[execing], NULL, 0);
+           rc = do_spawn_ve(aTHX_ really, argv, flag, execf[execing], NULL, 0);
        }
     } else
        rc = -1;
-    do_execfree();
+    LEAVE;
     return rc;
 }
 
index b078586..337769b 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -4480,7 +4480,6 @@ PP(pp_system)
            (void)rsignal_restore(SIGQUIT, &qhand);
 #endif
            STATUS_NATIVE_CHILD_SET(result == -1 ? -1 : status);
-           do_execfree();      /* free any memory child malloced on fork */
            SP = ORIGMARK;
            if (did_pipes) {
                int errkid;
@@ -4559,7 +4558,6 @@ PP(pp_system)
     if (PL_statusvalue == -1)  /* hint that value must be returned as is */
        result = 1;
     STATUS_NATIVE_CHILD_SET(value);
-    do_execfree();
     SP = ORIGMARK;
     XPUSHi(result ? value : STATUS_CURRENT);
 #endif /* !FORK or VMS or OS/2 */
diff --git a/proto.h b/proto.h
index 2a2f25a..80981d4 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -744,7 +744,6 @@ PERL_CALLCONV void  Perl_do_dump_pad(pTHX_ I32 level, PerlIO *file, PADLIST *padl
 PERL_CALLCONV bool     Perl_do_eof(pTHX_ GV* gv);
 #define PERL_ARGS_ASSERT_DO_EOF        \
        assert(gv)
-PERL_CALLCONV void     Perl_do_execfree(pTHX);
 PERL_CALLCONV void     Perl_do_gv_dump(pTHX_ I32 level, PerlIO *file, const char *name, GV *sv);
 #define PERL_ARGS_ASSERT_DO_GV_DUMP    \
        assert(file); assert(name)
diff --git a/sv.c b/sv.c
index 924a7e3..4f45992 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -15174,8 +15174,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_filemode                = proto_perl->Ifilemode;
     PL_lastfd          = proto_perl->Ilastfd;
     PL_oldname         = proto_perl->Ioldname;         /* XXX not quite right */
-    PL_Argv            = NULL;
-    PL_Cmd             = NULL;
     PL_gensym          = proto_perl->Igensym;
 
     PL_laststatval     = proto_perl->Ilaststatval;
diff --git a/util.c b/util.c
index 9c989a6..f89922c 100644 (file)
--- a/util.c
+++ b/util.c
@@ -2300,7 +2300,6 @@ Perl_my_popen_list(pTHX_ const char *mode, int n, SV **args)
 #undef THAT
     }
     /* Parent */
-    do_execfree();     /* free any memory malloced by child on fork */
     if (did_pipes)
        PerlLIO_close(pp[1]);
     /* Keep the lower of the two fd numbers */
@@ -2459,7 +2458,6 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode)
 #undef THIS
 #undef THAT
     }
-    do_execfree();     /* free any memory malloced by child on vfork */
     if (did_pipes)
        PerlLIO_close(pp[1]);
     if (p[that] < p[This]) {
index 83e38f1..7698fac 100644 (file)
--- a/vms/vms.c
+++ b/vms/vms.c
@@ -10485,7 +10485,7 @@ vms_execfree(struct dsc$descriptor_s *vmscmd)
 static char *
 setup_argstr(pTHX_ SV *really, SV **mark, SV **sp)
 {
-  char *junk, *tmps = NULL;
+  char *junk, *tmps = NULL, *cmd;
   size_t cmdlen = 0;
   size_t rlen;
   SV **idx;
@@ -10506,22 +10506,23 @@ setup_argstr(pTHX_ SV *really, SV **mark, SV **sp)
       cmdlen += rlen ? rlen + 1 : 0;
     }
   }
-  Newx(PL_Cmd, cmdlen+1, char);
+  Newx(cmd, cmdlen+1, char);
+  SAVEFREEPV(cmd);
 
   if (tmps && *tmps) {
-    my_strlcpy(PL_Cmd, tmps, cmdlen + 1);
+    my_strlcpy(cmd, tmps, cmdlen + 1);
     mark++;
   }
-  else *PL_Cmd = '\0';
+  else *cmd = '\0';
   while (++mark <= sp) {
     if (*mark) {
       char *s = SvPVx(*mark,n_a);
       if (!*s) continue;
-      if (*PL_Cmd) my_strlcat(PL_Cmd, " ", cmdlen+1);
-      my_strlcat(PL_Cmd, s, cmdlen+1);
+      if (*cmd) my_strlcat(cmd, " ", cmdlen+1);
+      my_strlcat(cmd, s, cmdlen+1);
     }
   }
-  return PL_Cmd;
+  return cmd;
 
 }  /* end of setup_argstr() */
 
@@ -10948,9 +10949,10 @@ Perl_vms_do_aexec(pTHX_ SV *really,SV **mark,SV **sp)
   }
                                            /* no vfork - act VMSish */
   if (sp > mark) {
+    ENTER;
     cmd = setup_argstr(aTHX_ really,mark,sp);
     exec_sts = vms_do_exec(cmd);
-    Safefree(cmd);  /* Clean up from setup_argstr() */
+    LEAVE;
     return exec_sts;
   }
 
@@ -11039,8 +11041,10 @@ Perl_do_aspawn(pTHX_ SV* really, SV** mark, SV** sp)
     else
         flags = 0;
 
+    ENTER;
     cmd = setup_argstr(aTHX_ really, mark, sp);
     sts = do_spawn2(aTHX_ cmd, flags);
+    LEAVE;
     /* pp_sys will clean up cmd */
     return sts;
   }
@@ -11075,9 +11079,6 @@ do_spawn2(pTHX_ const char *cmd, int flags)
 {
   unsigned long int sts, substs;
 
-  /* The caller of this routine expects to Safefree(PL_Cmd) */
-  Newx(PL_Cmd,10,char);
-
   TAINT_ENV();
   TAINT_PROPER("spawn");
   if (!cmd || !*cmd) {