Skip to content

Commit e00c55d

Browse files
committed
main: quote output file name before passing it to system(3) function
Following command line doesn't work: $ ctags -o 'a b' ... because a shell lauched from system(3) deals a whitespace between 'a' and 'b' as a separator. The output file name is passed to system(3) to run external sort command. This commit adds code to put double and single quoets around the output file name before passing it to system(3). The issue is reported by Lorenz Hipp <[email protected]> in a private mail. Signed-off-by: Masatake YAMATO <[email protected]>
1 parent 6e839be commit e00c55d

File tree

5 files changed

+102
-18
lines changed

5 files changed

+102
-18
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int x;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright: 2016 Masatake YAMATO
2+
# License: GPL-2
3+
4+
CTAGS=$1
5+
6+
rm -f ./"'"
7+
rm -f ./'"'
8+
rm -f ./'$(ls)'
9+
rm -f ./'a b'
10+
11+
${CTAGS} --quiet --options=NONE -o ./"'" --extra=-pF input.c
12+
${CTAGS} --quiet --options=NONE -o ./'"' --extra=-pF input.c
13+
${CTAGS} --quiet --options=NONE -o ./'$(ls)' --extra=-pF input.c
14+
${CTAGS} --quiet --options=NONE -o ./'a b' --extra=-pF input.c
15+
16+
echo '#' SINGLE QUOTE
17+
if [ -e "'" ]; then
18+
cat "'"
19+
fi
20+
21+
echo '#' DOUBLE QUOTES
22+
if [ -e '"' ]; then
23+
cat '"'
24+
fi
25+
26+
echo '#' PROCESS SUBSTITUTION
27+
if [ -e '$(ls)' ]; then
28+
cat '$(ls)'
29+
fi
30+
31+
echo '#' SPACE
32+
if [ -e 'a b' ]; then
33+
cat 'a b'
34+
fi
35+
36+
rm -f ./"'"
37+
rm -f ./'"'
38+
rm -f ./'$(ls)'
39+
rm -f ./'a b'

Tmain/abnormal-output-file-names.d/stderr-expected.txt

Whitespace-only changes.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SINGLE QUOTE
2+
x input.c /^int x;$/;" v typeref:typename:int
3+
# DOUBLE QUOTES
4+
x input.c /^int x;$/;" v typeref:typename:int
5+
# PROCESS SUBSTITUTION
6+
x input.c /^int x;$/;" v typeref:typename:int
7+
# SPACE
8+
x input.c /^int x;$/;" v typeref:typename:int

main/sort.c

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,44 @@ extern void catFile (MIO *mio)
5555
# define PE_CONST const
5656
#endif
5757

58+
/*
59+
Output file name should not be evaluated in system(3) function.
60+
The name must be used as is. Quotations are required to block the
61+
evaluation.
62+
63+
Normal single-quotes are used to quote a cstring:
64+
a => 'a'
65+
" => '"'
66+
67+
If a single-quote is included in the cstring, use double quotes for quoting it.
68+
' => ''"'"''
69+
*/
70+
static void appendCstringWithQuotes (vString *dest, const char* cstr)
71+
{
72+
const char* o;
73+
74+
vStringPut (dest, '\'');
75+
for (o = cstr; *o; o++)
76+
{
77+
if (*o == '\'')
78+
vStringCatS (dest, "'\"'\"'");
79+
else
80+
vStringPut (dest, *o);
81+
}
82+
vStringPut (dest, '\'');
83+
}
84+
5885
extern void externalSortTags (const bool toStdout, MIO *tagFile)
5986
{
6087
const char *const sortNormalCommand = "sort -u";
6188
const char *const sortFoldedCommand = "sort -u -f";
6289
const char *sortCommand =
6390
Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand;
91+
# ifndef HAVE_SETENV
6492
PE_CONST char *const sortOrder1 = "LC_COLLATE=C";
6593
PE_CONST char *const sortOrder2 = "LC_ALL=C";
66-
const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) +
67-
strlen (sortCommand) + (2 * strlen (tagFileName ()));
68-
char *const cmd = (char *) malloc (length + 1);
94+
# endif
95+
vString *cmd = vStringNew ();
6996
int ret = -1;
7097

7198
if (cmd != NULL)
@@ -80,19 +107,29 @@ extern void externalSortTags (const bool toStdout, MIO *tagFile)
80107
putenv (sortOrder1);
81108
putenv (sortOrder2);
82109
# endif
83-
if (toStdout)
84-
sprintf (cmd, "%s", sortCommand);
85-
else
86-
sprintf (cmd, "%s -o %s %s", sortCommand,
87-
tagFileName (), tagFileName ());
110+
vStringCatS (cmd, sortCommand);
111+
if (! toStdout)
112+
{
113+
vStringCatS (cmd, " -o ");
114+
appendCstringWithQuotes (cmd, tagFileName ());
115+
vStringPut (cmd, ' ');
116+
appendCstringWithQuotes (cmd, tagFileName ());
117+
}
88118
#else
89-
if (toStdout)
90-
sprintf (cmd, "%s %s %s", sortOrder1, sortOrder2, sortCommand);
91-
else
92-
sprintf (cmd, "%s %s %s -o %s %s", sortOrder1, sortOrder2,
93-
sortCommand, tagFileName (), tagFileName ());
119+
vStringCatS (cmd, sortOrder1);
120+
vStringPut (cmd, ' ');
121+
vStringCatS (cmd, sortOrder2);
122+
vStringPut (cmd, ' ');
123+
vStringCatS (cmd, sortCommand);
124+
if (! toStdout)
125+
{
126+
vStringCats (cmd, " -o ");
127+
appendCstringWithQuotes (cmd, tagFileName ());
128+
vStringPut (cmd, ' ');
129+
appendCstringWithQuotes (cmd, tagFileName ());
130+
}
94131
#endif
95-
verbose ("system (\"%s\")\n", cmd);
132+
verbose ("system (\"%s\")\n", vStringValue (cmd));
96133
if (toStdout)
97134
{
98135
const int fdstdin = 0;
@@ -105,15 +142,14 @@ extern void externalSortTags (const bool toStdout, MIO *tagFile)
105142
error (FATAL | PERROR, "cannot redirect stdin");
106143
if (lseek (fdstdin, 0, SEEK_SET) != 0)
107144
error (FATAL | PERROR, "cannot rewind tag file");
108-
ret = system (cmd);
145+
ret = system (vStringValue (cmd));
109146
if (dup2 (fdsave, fdstdin) < 0)
110147
error (FATAL | PERROR, "cannot restore stdin fd");
111148
close (fdsave);
112149
}
113150
else
114-
ret = system (cmd);
115-
free (cmd);
116-
151+
ret = system (vStringValue (cmd));
152+
vStringDelete (cmd);
117153
}
118154
if (ret != 0)
119155
error (FATAL | PERROR, "cannot sort tag file");

0 commit comments

Comments
 (0)