[git commit] xargs: fix handling of quoted arguments, closes 11441
Denys Vlasenko
vda.linux at googlemail.com
Wed Jan 29 13:39:13 UTC 2020
commit: https://git.busybox.net/busybox/commit/?id=1ff7002b1d229c678fdffebec602fb4c54439a31
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master
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 at pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
findutils/xargs.c | 27 ++++++++++++++++++---------
testsuite/xargs.tests | 9 +++++++++
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 {
int max_procs;
#endif
smalluint xargs_exitcode;
+#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
+#define NORM 0
+#define QUOTE 1
+#define BACKSLASH 2
+#define SPACE 4
+ smalluint process_stdin__state;
+ char process_stdin__q;
+#endif
} FIX_ALIASING;
#define G (*(struct globals*)bb_common_bufsiz1)
#define INIT_G() do { \
setup_common_bufsiz(); \
- G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \
+ IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \
+ IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \
+ /* Even zero values are set because we are NOEXEC applet */ \
+ G.eof_str = NULL; \
G.idx = 0; \
IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \
IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \
G.xargs_exitcode = 0; \
- IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \
- IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \
+ IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \
+ IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \
} while (0)
@@ -257,12 +268,8 @@ static void store_param(char *s)
#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
{
-#define NORM 0
-#define QUOTE 1
-#define BACKSLASH 2
-#define SPACE 4
- char q = '\0'; /* quote char */
- char state = NORM;
+#define q G.process_stdin__q
+#define state G.process_stdin__state
char *s = buf; /* start of the word */
char *p = s + strlen(buf); /* end of the word */
@@ -339,6 +346,8 @@ static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
/* store_param(NULL) - caller will do it */
dbg_msg("return:'%s'", s);
return s;
+#undef q
+#undef state
}
#else
/* 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" \
"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" \
"" "2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 00\n"
+# see that we don't get "argument line too long",
+# but do see the last word, 99999, instead
+optional FEATURE_XARGS_SUPPORT_QUOTES
+testing "xargs argument line too long" \
+ "seq 10000 99999 | sed -e 's/^/\"/' -e 's/$/\"/' | xargs echo | grep -o 99999; echo \$?" \
+ "99999\n0\n" \
+ "" ""
+SKIP=
+
exit $FAILCOUNT
More information about the busybox-cvs
mailing list