aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-01-24 13:16:45 +0000
committerDenys Vlasenko <vda.linux@googlemail.com>2020-01-29 14:39:13 +0100
commit1ff7002b1d229c678fdffebec602fb4c54439a31 (patch)
tree71b5f1f29037301c29e6ce41ddca51da3cd237ce
parent16bcd504a32e6a7bf2015ffb241133f9ead6100b (diff)
downloadbusybox-w32-1ff7002b1d229c678fdffebec602fb4c54439a31.tar.gz
busybox-w32-1ff7002b1d229c678fdffebec602fb4c54439a31.tar.bz2
busybox-w32-1ff7002b1d229c678fdffebec602fb4c54439a31.zip
xargs: fix handling of quoted arguments, closes 11441
As reported in bug 11441 when presented with a large number of quoted arguments xargs can return 'argument line too long': seq 10000 29999 | sed -e 's/^/"/' -e 's/$/"/' | busybox xargs echo This happens because the variant of process_stdin() which handles quoted arguments doesn't preserve state between calls. If the allowed number of characters is exceeded part way through a quoted argument the next call to process_stdin() incorrectly treats the terminating quote as a starting quote, thus quoting all of the argument separators. function old new delta process_stdin 274 303 +29 xargs_main 731 745 +14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 43/0) Total: 43 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--findutils/xargs.c27
-rwxr-xr-xtestsuite/xargs.tests9
2 files changed, 27 insertions, 9 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 726315803..4fb306bb8 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -114,17 +114,28 @@ struct globals {
114 int max_procs; 114 int max_procs;
115#endif 115#endif
116 smalluint xargs_exitcode; 116 smalluint xargs_exitcode;
117#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
118#define NORM 0
119#define QUOTE 1
120#define BACKSLASH 2
121#define SPACE 4
122 smalluint process_stdin__state;
123 char process_stdin__q;
124#endif
117} FIX_ALIASING; 125} FIX_ALIASING;
118#define G (*(struct globals*)bb_common_bufsiz1) 126#define G (*(struct globals*)bb_common_bufsiz1)
119#define INIT_G() do { \ 127#define INIT_G() do { \
120 setup_common_bufsiz(); \ 128 setup_common_bufsiz(); \
121 G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ 129 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \
130 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \
131 /* Even zero values are set because we are NOEXEC applet */ \
132 G.eof_str = NULL; \
122 G.idx = 0; \ 133 G.idx = 0; \
123 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ 134 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \
124 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ 135 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \
125 G.xargs_exitcode = 0; \ 136 G.xargs_exitcode = 0; \
126 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \ 137 IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \
127 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \ 138 IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \
128} while (0) 139} while (0)
129 140
130 141
@@ -257,12 +268,8 @@ static void store_param(char *s)
257#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 268#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
258static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) 269static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
259{ 270{
260#define NORM 0 271#define q G.process_stdin__q
261#define QUOTE 1 272#define state G.process_stdin__state
262#define BACKSLASH 2
263#define SPACE 4
264 char q = '\0'; /* quote char */
265 char state = NORM;
266 char *s = buf; /* start of the word */ 273 char *s = buf; /* start of the word */
267 char *p = s + strlen(buf); /* end of the word */ 274 char *p = s + strlen(buf); /* end of the word */
268 275
@@ -339,6 +346,8 @@ static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
339 /* store_param(NULL) - caller will do it */ 346 /* store_param(NULL) - caller will do it */
340 dbg_msg("return:'%s'", s); 347 dbg_msg("return:'%s'", s);
341 return s; 348 return s;
349#undef q
350#undef state
342} 351}
343#else 352#else
344/* The variant does not support single quotes, double quotes or backslash */ 353/* The variant does not support single quotes, double quotes or backslash */
diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests
index 2d0a201b7..855b33bc2 100755
--- a/testsuite/xargs.tests
+++ b/testsuite/xargs.tests
@@ -41,4 +41,13 @@ testing "xargs -sNUM test 2" \
41 "echo 1 2 3 4 5 6 7 8 9 0\n""echo 1 2 3 4 5 6 7 8 9\n""echo 1 00\n" \ 41 "echo 1 2 3 4 5 6 7 8 9 0\n""echo 1 2 3 4 5 6 7 8 9\n""echo 1 00\n" \
42 "" "2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 00\n" 42 "" "2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 00\n"
43 43
44# see that we don't get "argument line too long",
45# but do see the last word, 99999, instead
46optional FEATURE_XARGS_SUPPORT_QUOTES
47testing "xargs argument line too long" \
48 "seq 10000 99999 | sed -e 's/^/\"/' -e 's/$/\"/' | xargs echo | grep -o 99999; echo \$?" \
49 "99999\n0\n" \
50 "" ""
51SKIP=
52
44exit $FAILCOUNT 53exit $FAILCOUNT