summaryrefslogtreecommitdiff
path: root/os2
diff options
context:
space:
mode:
authorZefram <zefram@fysh.org>2017-12-06 21:27:15 +0000
committerZefram <zefram@fysh.org>2017-12-14 22:48:30 +0000
commit282fc0b3cc2439f69587d980b62bef7f5d5bdfef (patch)
tree6dc6abf858b4903d0adb99d6309a74f84ebf7782 /os2
parente135ff695231a81e2a70a739e8d813525432fd4d (diff)
downloadperl-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.c109
1 files changed, 61 insertions, 48 deletions
diff --git a/os2/os2.c b/os2/os2.c
index 66f387bd3c..54c7ef18d9 100644
--- 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;
}