diff options
author | Zefram <zefram@fysh.org> | 2017-12-06 21:27:15 +0000 |
---|---|---|
committer | Zefram <zefram@fysh.org> | 2017-12-14 22:48:30 +0000 |
commit | 282fc0b3cc2439f69587d980b62bef7f5d5bdfef (patch) | |
tree | 6dc6abf858b4903d0adb99d6309a74f84ebf7782 /os2 | |
parent | e135ff695231a81e2a70a739e8d813525432fd4d (diff) | |
download | perl-282fc0b3cc2439f69587d980b62bef7f5d5bdfef.tar.gz |
make exec keep its argument list more reliably
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].
Diffstat (limited to 'os2')
-rw-r--r-- | os2/os2.c | 109 |
1 files changed, 61 insertions, 48 deletions
@@ -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; } |