Skip to content

Commit 282fc0b

Browse files
author
Zefram
committed
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].
1 parent e135ff6 commit 282fc0b

File tree

14 files changed

+186
-166
lines changed

14 files changed

+186
-166
lines changed

amigaos4/amigaio.c

+35-31
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ static void S_exec_failed(pTHX_ const char *cmd, int fd, int do_report)
646646
static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
647647
{
648648
dVAR;
649-
const char **a;
649+
const char **argv, **a;
650650
char *s;
651651
char *buf;
652652
char *cmd;
@@ -656,7 +656,9 @@ static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
656656

657657
PERL_ARGS_ASSERT_DO_EXEC3;
658658

659+
ENTER;
659660
Newx(buf, cmdlen, char);
661+
SAVEFREEPV(buf);
660662
cmd = buf;
661663
memcpy(cmd, incmd, cmdlen);
662664

@@ -709,15 +711,16 @@ static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
709711
PERL_FPU_POST_EXEC
710712
S_exec_failed(aTHX_ PL_sh_path, fd, do_report);
711713
amigaos_post_exec(fd, do_report);
712-
Safefree(buf);
713-
return result;
714+
goto leave;
714715
}
715716
}
716717

717-
Newx(PL_Argv, (s - cmd) / 2 + 2, const char *);
718-
PL_Cmd = savepvn(cmd, s - cmd);
719-
a = PL_Argv;
720-
for (s = PL_Cmd; *s;)
718+
Newx(argv, (s - cmd) / 2 + 2, const char *);
719+
SAVEFREEPV(argv);
720+
cmd = savepvn(cmd, s - cmd);
721+
SAVEFREEPV(cmd);
722+
a = argv;
723+
for (s = cmd; *s;)
721724
{
722725
while (isSPACE(*s))
723726
s++;
@@ -729,22 +732,18 @@ static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
729732
*s++ = '\0';
730733
}
731734
*a = NULL;
732-
if (PL_Argv[0])
735+
if (argv[0])
733736
{
734737
PERL_FPU_PRE_EXEC
735-
result = myexecvp(FALSE, PL_Argv[0], EXEC_ARGV_CAST(PL_Argv));
738+
result = myexecvp(FALSE, argv[0], EXEC_ARGV_CAST(argv));
736739
PERL_FPU_POST_EXEC
737-
if (errno == ENOEXEC)
738-
{
739-
/* for system V NIH syndrome */
740-
do_execfree();
740+
if (errno == ENOEXEC) /* for system V NIH syndrome */
741741
goto doshell;
742-
}
743-
S_exec_failed(aTHX_ PL_Argv[0], fd, do_report);
742+
S_exec_failed(aTHX_ argv[0], fd, do_report);
744743
amigaos_post_exec(fd, do_report);
745744
}
746-
do_execfree();
747-
Safefree(buf);
745+
leave:
746+
LEAVE;
748747
return result;
749748
}
750749

@@ -754,42 +753,47 @@ I32 S_do_amigaos_aexec5(
754753
dVAR;
755754
I32 result = -1;
756755
PERL_ARGS_ASSERT_DO_AEXEC5;
756+
ENTER;
757757
if (sp > mark)
758758
{
759-
const char **a;
759+
const char **argv, **a;
760760
const char *tmps = NULL;
761-
Newx(PL_Argv, sp - mark + 1, const char *);
762-
a = PL_Argv;
761+
Newx(argv, sp - mark + 1, const char *);
762+
SAVEFREEPV(argv);
763+
a = argv;
763764

764765
while (++mark <= sp)
765766
{
766-
if (*mark)
767-
*a++ = SvPV_nolen_const(*mark);
768-
else
767+
if (*mark) {
768+
char *arg = savepv(SvPV_nolen_const(*mark));
769+
SAVEFREEPV(arg);
770+
*a++ = arg;
771+
} else
769772
*a++ = "";
770773
}
771774
*a = NULL;
772-
if (really)
773-
tmps = SvPV_nolen_const(really);
774-
if ((!really && *PL_Argv[0] != '/') ||
775+
if (really) {
776+
tmps = savepv(SvPV_nolen_const(really));
777+
SAVEFREEPV(tmps);
778+
}
779+
if ((!really && *argv[0] != '/') ||
775780
(really && *tmps != '/')) /* will execvp use PATH? */
776781
TAINT_ENV(); /* testing IFS here is overkill, probably
777782
*/
778783
PERL_FPU_PRE_EXEC
779784
if (really && *tmps)
780785
{
781-
result = myexecvp(FALSE, tmps, EXEC_ARGV_CAST(PL_Argv));
786+
result = myexecvp(FALSE, tmps, EXEC_ARGV_CAST(argv));
782787
}
783788
else
784789
{
785-
result = myexecvp(FALSE, PL_Argv[0],
786-
EXEC_ARGV_CAST(PL_Argv));
790+
result = myexecvp(FALSE, argv[0], EXEC_ARGV_CAST(argv));
787791
}
788792
PERL_FPU_POST_EXEC
789-
S_exec_failed(aTHX_(really ? tmps : PL_Argv[0]), fd, do_report);
793+
S_exec_failed(aTHX_(really ? tmps : argv[0]), fd, do_report);
790794
}
791795
amigaos_post_exec(fd, do_report);
792-
do_execfree();
796+
LEAVE;
793797
return result;
794798
}
795799

cygwin/cygwin.c

+18-10
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ int
9090
do_spawn (char *cmd)
9191
{
9292
dTHX;
93-
char const **a;
93+
char const **argv, **a;
9494
char *s;
9595
char const *metachars = "$&*(){}[]'\";\\?>|<~`\n";
9696
const char *command[4];
97+
int result;
9798

99+
ENTER;
98100
while (*cmd && isSPACE(*cmd))
99101
cmd++;
100102

@@ -127,13 +129,16 @@ do_spawn (char *cmd)
127129
command[2] = cmd;
128130
command[3] = NULL;
129131

130-
return do_spawnvp("sh",command);
132+
result = do_spawnvp("sh",command);
133+
goto leave;
131134
}
132135

133-
Newx (PL_Argv, (s-cmd)/2+2, const char*);
134-
PL_Cmd=savepvn (cmd,s-cmd);
135-
a=PL_Argv;
136-
for (s=PL_Cmd; *s;) {
136+
Newx (argv, (s-cmd)/2+2, const char*);
137+
SAVEFREEPV(argv);
138+
cmd=savepvn (cmd,s-cmd);
139+
SAVEFREEPV(cmd);
140+
a=argv;
141+
for (s=cmd; *s;) {
137142
while (*s && isSPACE (*s)) s++;
138143
if (*s)
139144
*(a++)=s;
@@ -142,10 +147,13 @@ do_spawn (char *cmd)
142147
*s++='\0';
143148
}
144149
*a = (char*)NULL;
145-
if (!PL_Argv[0])
146-
return -1;
147-
148-
return do_spawnvp(PL_Argv[0],(const char * const *)PL_Argv);
150+
if (!argv[0])
151+
result = -1;
152+
else
153+
result = do_spawnvp(argv[0],(const char * const *)argv);
154+
leave:
155+
LEAVE;
156+
return result;
149157
}
150158

151159
#if (CYGWIN_VERSION_API_MINOR >= 181)

djgpp/djgpp.c

+23-13
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,10 @@ do_aspawn (pTHX_ SV *really,SV **mark,SV **sp)
150150
int
151151
do_spawn2 (pTHX_ char *cmd,int execf)
152152
{
153-
char **a,*s,*shell,*metachars;
154-
int rc,unixysh;
153+
char **argv,**a,*s,*shell,*metachars;
154+
int rc,unixysh,result;
155155

156+
ENTER;
156157
if ((shell=getenv("SHELL"))==NULL && (shell=getenv("COMSPEC"))==NULL)
157158
shell="c:\\command.com" EXTRA;
158159

@@ -189,14 +190,18 @@ do_spawn2 (pTHX_ char *cmd,int execf)
189190
}
190191
doshell:
191192
if (execf==EXECF_EXEC)
192-
return convretcode (execl (shell,shell,unixysh ? "-c" : "/c",cmd,NULL),cmd,execf);
193-
return convretcode (system (cmd),cmd,execf);
193+
result = convretcode (execl (shell,shell,unixysh ? "-c" : "/c",cmd,NULL),cmd,execf);
194+
else
195+
result = convretcode (system (cmd),cmd,execf);
196+
goto leave;
194197
}
195198

196-
Newx (PL_Argv,(s-cmd)/2+2,char*);
197-
PL_Cmd=savepvn (cmd,s-cmd);
198-
a=PL_Argv;
199-
for (s=PL_Cmd; *s;) {
199+
Newx (argv,(s-cmd)/2+2,char*);
200+
SAVEFREEPV(argv);
201+
cmd=savepvn (cmd,s-cmd);
202+
SAVEFREEPV(cmd);
203+
a=argv;
204+
for (s=cmd; *s;) {
200205
while (*s && isSPACE (*s)) s++;
201206
if (*s)
202207
*(a++)=s;
@@ -205,14 +210,19 @@ do_spawn2 (pTHX_ char *cmd,int execf)
205210
*s++='\0';
206211
}
207212
*a=NULL;
208-
if (!PL_Argv[0])
209-
return -1;
213+
if (!argv[0]) {
214+
result = -1;
215+
goto leave;
216+
}
210217

211218
if (execf==EXECF_EXEC)
212-
rc=execvp (PL_Argv[0],PL_Argv);
219+
rc=execvp (argv[0],argv);
213220
else
214-
rc=spawnvp (P_WAIT,PL_Argv[0],PL_Argv);
215-
return convretcode (rc,PL_Argv[0],execf);
221+
rc=spawnvp (P_WAIT,argv[0],argv);
222+
result = convretcode (rc,argv[0],execf);
223+
leave:
224+
LEAVE;
225+
return result;
216226
}
217227

218228
int

doio.c

+37-40
Original file line numberDiff line numberDiff line change
@@ -1992,56 +1992,53 @@ Perl_do_aexec5(pTHX_ SV *really, SV **mark, SV **sp,
19921992
Perl_croak(aTHX_ "exec? I'm not *that* kind of operating system");
19931993
#else
19941994
assert(sp >= mark);
1995+
ENTER;
19951996
{
1996-
const char **a;
1997+
const char **argv, **a;
19971998
const char *tmps = NULL;
1998-
Newx(PL_Argv, sp - mark + 1, const char*);
1999-
a = PL_Argv;
1999+
Newx(argv, sp - mark + 1, const char*);
2000+
SAVEFREEPV(argv);
2001+
a = argv;
20002002

20012003
while (++mark <= sp) {
2002-
if (*mark)
2003-
*a++ = SvPV_nolen_const(*mark);
2004-
else
2004+
if (*mark) {
2005+
char *arg = savepv(SvPV_nolen_const(*mark));
2006+
SAVEFREEPV(arg);
2007+
*a++ = arg;
2008+
} else
20052009
*a++ = "";
20062010
}
20072011
*a = NULL;
2008-
if (really)
2009-
tmps = SvPV_nolen_const(really);
2010-
if ((!really && PL_Argv[0] && *PL_Argv[0] != '/') ||
2012+
if (really) {
2013+
tmps = savepv(SvPV_nolen_const(really));
2014+
SAVEFREEPV(tmps);
2015+
}
2016+
if ((!really && argv[0] && *argv[0] != '/') ||
20112017
(really && *tmps != '/')) /* will execvp use PATH? */
20122018
TAINT_ENV(); /* testing IFS here is overkill, probably */
20132019
PERL_FPU_PRE_EXEC
20142020
if (really && *tmps) {
2015-
PerlProc_execvp(tmps,EXEC_ARGV_CAST(PL_Argv));
2016-
} else if (PL_Argv[0]) {
2017-
PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
2021+
PerlProc_execvp(tmps,EXEC_ARGV_CAST(argv));
2022+
} else if (argv[0]) {
2023+
PerlProc_execvp(argv[0],EXEC_ARGV_CAST(argv));
20182024
} else {
20192025
SETERRNO(ENOENT,RMS_FNF);
20202026
}
20212027
PERL_FPU_POST_EXEC
2022-
S_exec_failed(aTHX_ (really ? tmps : PL_Argv[0] ? PL_Argv[0] : ""), fd, do_report);
2028+
S_exec_failed(aTHX_ (really ? tmps : argv[0] ? argv[0] : ""), fd, do_report);
20232029
}
2024-
do_execfree();
2030+
LEAVE;
20252031
#endif
20262032
return FALSE;
20272033
}
20282034

2029-
void
2030-
Perl_do_execfree(pTHX)
2031-
{
2032-
Safefree(PL_Argv);
2033-
PL_Argv = NULL;
2034-
Safefree(PL_Cmd);
2035-
PL_Cmd = NULL;
2036-
}
2037-
20382035
#ifdef PERL_DEFAULT_DO_EXEC3_IMPLEMENTATION
20392036

20402037
bool
20412038
Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
20422039
{
20432040
dVAR;
2044-
const char **a;
2041+
const char **argv, **a;
20452042
char *s;
20462043
char *buf;
20472044
char *cmd;
@@ -2050,7 +2047,9 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
20502047

20512048
PERL_ARGS_ASSERT_DO_EXEC3;
20522049

2050+
ENTER;
20532051
Newx(buf, cmdlen, char);
2052+
SAVEFREEPV(buf);
20542053
cmd = buf;
20552054
memcpy(cmd, incmd, cmdlen);
20562055

@@ -2086,8 +2085,7 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
20862085
PERL_FPU_POST_EXEC
20872086
*s = '\'';
20882087
S_exec_failed(aTHX_ PL_cshname, fd, do_report);
2089-
Safefree(buf);
2090-
return FALSE;
2088+
goto leave;
20912089
}
20922090
}
20932091
}
@@ -2134,15 +2132,16 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
21342132
PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL);
21352133
PERL_FPU_POST_EXEC
21362134
S_exec_failed(aTHX_ PL_sh_path, fd, do_report);
2137-
Safefree(buf);
2138-
return FALSE;
2135+
goto leave;
21392136
}
21402137
}
21412138

2142-
Newx(PL_Argv, (s - cmd) / 2 + 2, const char*);
2143-
PL_Cmd = savepvn(cmd, s-cmd);
2144-
a = PL_Argv;
2145-
for (s = PL_Cmd; *s;) {
2139+
Newx(argv, (s - cmd) / 2 + 2, const char*);
2140+
SAVEFREEPV(argv);
2141+
cmd = savepvn(cmd, s-cmd);
2142+
SAVEFREEPV(cmd);
2143+
a = argv;
2144+
for (s = cmd; *s;) {
21462145
while (isSPACE(*s))
21472146
s++;
21482147
if (*s)
@@ -2153,18 +2152,16 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
21532152
*s++ = '\0';
21542153
}
21552154
*a = NULL;
2156-
if (PL_Argv[0]) {
2155+
if (argv[0]) {
21572156
PERL_FPU_PRE_EXEC
2158-
PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
2157+
PerlProc_execvp(argv[0],EXEC_ARGV_CAST(argv));
21592158
PERL_FPU_POST_EXEC
2160-
if (errno == ENOEXEC) { /* for system V NIH syndrome */
2161-
do_execfree();
2159+
if (errno == ENOEXEC) /* for system V NIH syndrome */
21622160
goto doshell;
2163-
}
2164-
S_exec_failed(aTHX_ PL_Argv[0], fd, do_report);
2161+
S_exec_failed(aTHX_ argv[0], fd, do_report);
21652162
}
2166-
do_execfree();
2167-
Safefree(buf);
2163+
leave:
2164+
LEAVE;
21682165
return FALSE;
21692166
}
21702167

0 commit comments

Comments
 (0)