1 /* Test of quotearg family of functions.
2    Copyright (C) 2008-2021 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, see <https://www.gnu.org/licenses/>.  */
16 
17 /* Written by Eric Blake <ebb9@byu.net>, 2008.  */
18 
19 #include <config.h>
20 
21 #include "quotearg.h"
22 
23 #include <ctype.h>
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "localcharset.h"
30 #include "macros.h"
31 #include "zerosize-ptr.h"
32 
33 #include "test-quotearg.h"
34 
35 static struct result_groups results_g[] = {
36   /* literal_quoting_style */
37   { { "", "\0""1\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
38       "a' b", LQ RQ, LQ RQ },
39     { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
40       "a' b", LQ RQ, LQ RQ },
41     { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
42       "a' b", LQ RQ, LQ RQ } },
43 
44   /* shell_quoting_style */
45   { { "''", "\0""1\0", 3, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
46       "'a\\b'", "\"a' b\"", LQ RQ, LQ RQ },
47     { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
48       "'a\\b'", "\"a' b\"", LQ RQ, LQ RQ },
49     { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
50       "'a\\b'", "\"a' b\"", LQ RQ, LQ RQ } },
51 
52   /* shell_always_quoting_style */
53   { { "''", "'\0""1\0'", 5, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
54       "'a\\b'", "\"a' b\"", "'" LQ RQ "'", "'" LQ RQ "'" },
55     { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
56       "'a\\b'", "\"a' b\"", "'" LQ RQ "'", "'" LQ RQ "'" },
57     { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
58       "'a\\b'", "\"a' b\"", "'" LQ RQ "'", "'" LQ RQ "'" } },
59 
60   /* shell_escape_quoting_style */
61   { { "''", "''$'\\0''1'$'\\0'", 15, "simple",
62       "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "a:b",
63       "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", LQ RQ },
64     { "''", "''$'\\0''1'$'\\0'", 15, "simple",
65       "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "a:b",
66       "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", LQ RQ },
67     { "''", "''$'\\0''1'$'\\0'", 15, "simple",
68       "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
69       "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", LQ RQ } },
70 
71   /* shell_escape_always_quoting_style */
72   { { "''", "''$'\\0''1'$'\\0'", 15, "'simple'",
73       "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
74       "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
75     { "''", "''$'\\0''1'$'\\0'", 15, "'simple'",
76       "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
77       "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
78     { "''", "''$'\\0''1'$'\\0'", 15, "'simple'",
79       "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
80       "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
81 
82   /* c_quoting_style */
83   { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
84       "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
85       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
86     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
87       "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
88       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
89     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
90       "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
91       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } },
92 
93   /* c_maybe_quoting_style */
94   { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
95       "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
96     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
97       "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
98     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
99       "\"a:b\"", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ } },
100 
101   /* escape_quoting_style */
102   { { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
103       "a\\\\b", "a' b", LQ_ENC RQ_ENC, LQ RQ },
104     { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
105       "a\\\\b", "a' b", LQ_ENC RQ_ENC, LQ RQ },
106     { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a\\:b",
107       "a\\\\b", "a' b", LQ_ENC RQ_ENC, LQ RQ } },
108 
109   /* locale_quoting_style */
110   { { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
111       "'a:b'", "'a\\\\b'", "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
112     { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
113       "'a:b'", "'a\\\\b'", "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
114     { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
115       "'a\\:b'", "'a\\\\b'", "'a\\' b'",
116       "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
117 
118   /* clocale_quoting_style */
119   { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
120       "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
121       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
122     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
123       "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
124       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
125     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
126       "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
127       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } }
128 };
129 
130 static struct result_groups flag_results[] = {
131   /* literal_quoting_style and QA_ELIDE_NULL_BYTES */
132   { { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", "a' b",
133       LQ RQ, LQ RQ },
134     { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", "a' b",
135       LQ RQ, LQ RQ },
136     { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", "a' b",
137       LQ RQ, LQ RQ } },
138 
139   /* c_quoting_style and QA_ELIDE_OUTER_QUOTES */
140   { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
141       "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
142     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
143       "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
144     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
145       "\"a:b\"", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ } },
146 
147   /* c_quoting_style and QA_SPLIT_TRIGRAPHS */
148   { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
149       "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
150       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
151     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
152       "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
153       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
154     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
155       "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
156       "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } }
157 };
158 
159 static char const *custom_quotes[][2] = {
160   { "", ""  },
161   { "'", "'"  },
162   { "(", ")"  },
163   { ":", " "  },
164   { " ", ":"  },
165   { "# ", "\n" },
166   { "\"'", "'\"" }
167 };
168 
169 static struct result_groups custom_results[] = {
170   /* left_quote = right_quote = "" */
171   { { "", "\\0001\\0", 7, "simple",
172       " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
173       "a' b", LQ_ENC RQ_ENC, LQ RQ },
174     { "", "\\0001\\0", 7, "simple",
175       " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
176       "a' b", LQ_ENC RQ_ENC, LQ RQ },
177     { "", "\\0001\\0", 7, "simple",
178       " \\t\\n'\"\\033?""?/\\\\", "a\\:b", "a\\\\b",
179       "a' b", LQ_ENC RQ_ENC, LQ RQ } },
180 
181   /* left_quote = right_quote = "'" */
182   { { "''", "'\\0001\\0'", 9, "'simple'",
183       "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
184       "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
185     { "''", "'\\0001\\0'", 9, "'simple'",
186       "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
187       "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
188     { "''", "'\\0001\\0'", 9, "'simple'",
189       "' \\t\\n\\'\"\\033?""?/\\\\'", "'a\\:b'", "'a\\\\b'",
190       "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
191 
192   /* left_quote = "(" and right_quote = ")" */
193   { { "()", "(\\0001\\0)", 9, "(simple)",
194       "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
195       "(a' b)", "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" },
196     { "()", "(\\0001\\0)", 9, "(simple)",
197       "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
198       "(a' b)", "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" },
199     { "()", "(\\0001\\0)", 9, "(simple)",
200       "( \\t\\n'\"\\033?""?/\\\\)", "(a\\:b)", "(a\\\\b)",
201       "(a' b)", "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" } },
202 
203   /* left_quote = ":" and right_quote = " " */
204   { { ": ", ":\\0001\\0 ", 9, ":simple ",
205       ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
206       ":a'\\ b ", ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " },
207     { ": ", ":\\0001\\0 ", 9, ":simple ",
208       ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
209       ":a'\\ b ", ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " },
210     { ": ", ":\\0001\\0 ", 9, ":simple ",
211       ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a\\:b ", ":a\\\\b ",
212       ":a'\\ b ", ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " } },
213 
214   /* left_quote = " " and right_quote = ":" */
215   { { " :", " \\0001\\0:", 9, " simple:",
216       "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
217       " a' b:", " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" },
218     { " :", " \\0001\\0:", 9, " simple:",
219       "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
220       " a' b:", " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" },
221     { " :", " \\0001\\0:", 9, " simple:",
222       "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
223       " a' b:", " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" } },
224 
225   /* left_quote = "# " and right_quote = "\n" */
226   { { "# \n", "# \\0001\\0\n", 10, "# simple\n",
227       "#  \\t\\n'\"\\033?""?/\\\\\n", "# a:b\n", "# a\\\\b\n",
228       "# a' b\n", "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" },
229     { "# \n", "# \\0001\\0\n", 10, "# simple\n",
230       "#  \\t\\n'\"\\033?""?/\\\\\n", "# a:b\n", "# a\\\\b\n",
231       "# a' b\n", "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" },
232     { "# \n", "# \\0001\\0\n", 10, "# simple\n",
233       "#  \\t\\n'\"\\033?""?/\\\\\n", "# a\\:b\n", "# a\\\\b\n",
234       "# a' b\n", "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" } },
235 
236   /* left_quote = "\"'" and right_quote = "'\"" */
237   { { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
238       "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a:b'\"", "\"'a\\\\b'\"",
239       "\"'a' b'\"", "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" },
240     { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
241       "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a:b'\"", "\"'a\\\\b'\"",
242       "\"'a' b'\"", "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" },
243     { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
244       "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a\\:b'\"", "\"'a\\\\b'\"",
245       "\"'a' b'\"", "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" } }
246 };
247 
248 static char *
use_quote_double_quotes(const char * str,size_t * len)249 use_quote_double_quotes (const char *str, size_t *len)
250 {
251   char *p = *len == SIZE_MAX ? quotearg_char (str, '"')
252                                : quotearg_char_mem (str, *len, '"');
253   *len = strlen (p);
254   return p;
255 }
256 
257 int
main(int argc _GL_UNUSED,char * argv[])258 main (int argc _GL_UNUSED, char *argv[])
259 {
260   int i;
261   bool ascii_only = MB_CUR_MAX == 1 && !isprint ((unsigned char) LQ[0]);
262 
263   /* This part of the program is hard-wired to the C locale since it
264      does not call setlocale.  However, according to POSIX, the use of
265      8-bit bytes in a character context in the C locale gives
266      unspecified results (that is, the C locale charset is allowed to
267      be unibyte with 8-bit bytes rejected [ASCII], unibyte with 8-bit
268      bytes being characters [often ISO-8859-1], or multibyte [often
269      UTF-8]).  We assume that the latter two cases will be
270      indistinguishable in this test - that is, the LQ and RQ sequences
271      will pass through unchanged in either type of charset.  So when
272      testing for quoting of str7, use the ascii_only flag to decide
273      what to expect for the 8-bit data being quoted.  */
274   ASSERT (!isprint ('\033'));
275   for (i = literal_quoting_style; i <= clocale_quoting_style; i++)
276     {
277       set_quoting_style (NULL, (enum quoting_style) i);
278       if (!(i == locale_quoting_style || i == clocale_quoting_style)
279           || (strcmp (locale_charset (), "ASCII") == 0
280               || strcmp (locale_charset (), "ANSI_X3.4-1968") == 0))
281         {
282           compare_strings (use_quotearg_buffer, &results_g[i].group1,
283                            ascii_only);
284           compare_strings (use_quotearg, &results_g[i].group2,
285                            ascii_only);
286           if (i == c_quoting_style)
287             compare_strings (use_quote_double_quotes, &results_g[i].group2,
288                              ascii_only);
289           compare_strings (use_quotearg_colon, &results_g[i].group3,
290                            ascii_only);
291         }
292     }
293 
294   set_quoting_style (NULL, literal_quoting_style);
295   ASSERT (set_quoting_flags (NULL, QA_ELIDE_NULL_BYTES) == 0);
296   compare_strings (use_quotearg_buffer, &flag_results[0].group1, ascii_only);
297   compare_strings (use_quotearg, &flag_results[0].group2, ascii_only);
298   compare_strings (use_quotearg_colon, &flag_results[0].group3, ascii_only);
299 
300   set_quoting_style (NULL, c_quoting_style);
301   ASSERT (set_quoting_flags (NULL, QA_ELIDE_OUTER_QUOTES)
302           == QA_ELIDE_NULL_BYTES);
303   compare_strings (use_quotearg_buffer, &flag_results[1].group1, ascii_only);
304   compare_strings (use_quotearg, &flag_results[1].group2, ascii_only);
305   compare_strings (use_quote_double_quotes, &flag_results[1].group2,
306                    ascii_only);
307   compare_strings (use_quotearg_colon, &flag_results[1].group3, ascii_only);
308 
309   ASSERT (set_quoting_flags (NULL, QA_SPLIT_TRIGRAPHS)
310           == QA_ELIDE_OUTER_QUOTES);
311   compare_strings (use_quotearg_buffer, &flag_results[2].group1, ascii_only);
312   compare_strings (use_quotearg, &flag_results[2].group2, ascii_only);
313   compare_strings (use_quote_double_quotes, &flag_results[2].group2,
314                    ascii_only);
315   compare_strings (use_quotearg_colon, &flag_results[2].group3, ascii_only);
316 
317   ASSERT (set_quoting_flags (NULL, 0) == QA_SPLIT_TRIGRAPHS);
318 
319   for (i = 0; i < sizeof custom_quotes / sizeof *custom_quotes; ++i)
320     {
321       set_custom_quoting (NULL,
322                           custom_quotes[i][0], custom_quotes[i][1]);
323       compare_strings (use_quotearg_buffer, &custom_results[i].group1,
324                        ascii_only);
325       compare_strings (use_quotearg, &custom_results[i].group2, ascii_only);
326       compare_strings (use_quotearg_colon, &custom_results[i].group3,
327                        ascii_only);
328     }
329 
330   {
331     /* Trigger the bug whereby quotearg_buffer would read beyond the NUL
332        that defines the end of the string being quoted.  Use an input
333        string whose NUL is the last byte before an unreadable page.  */
334     char *z = zerosize_ptr ();
335 
336     if (z)
337       {
338         size_t q_len = 1024;
339         char *q = malloc (q_len + 1);
340         char buf[10];
341         memset (q, 'Q', q_len);
342         q[q_len] = 0;
343 
344         /* Z points to the boundary between a readable/writable page
345            and one that is neither readable nor writable.  Position
346            our string so its NUL is at the end of the writable one.  */
347         char const *str = "____";
348         size_t s_len = strlen (str);
349         z -= s_len + 1;
350         memcpy (z, str, s_len + 1);
351 
352         set_custom_quoting (NULL, q, q);
353         /* Whether this actually triggers a SEGV depends on the
354            implementation of memcmp: whether it compares only byte-at-
355            a-time, and from left to right (no SEGV) or some other way.  */
356         size_t n = quotearg_buffer (buf, sizeof buf, z, SIZE_MAX, NULL);
357         ASSERT (n == s_len + 2 * q_len);
358         ASSERT (memcmp (buf, q, sizeof buf) == 0);
359         free (q);
360       }
361   }
362 
363   quotearg_free ();
364 
365   return 0;
366 }
367