From 1f5f147a9ec048897c43e2358223430098493497 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 24 Oct 2019 19:41:09 -0500 Subject: Fix the xargs argument too long problem by putting the proper accounting back when they haven't specified -s, add tests. --- tests/xargs.test | 9 +++++++++ toys/posix/xargs.c | 12 +++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/xargs.test b/tests/xargs.test index e2eec036..afed8a17 100644 --- a/tests/xargs.test +++ b/tests/xargs.test @@ -52,6 +52,15 @@ testing "false" "xargs false; echo \$?" "123\n" "" "" testing "exit 255" "xargs sh -c 'exit 255' 2>&1; echo \$?" \ "xargs: sh: exited with status 255; aborting\n124\n" "" "" +# findutils maxes out at 131066 (they do the math wrong), kernel takes 131071. +toyonly testing "max argument size" \ + "head -c 131071 /dev/zero | tr '\0' x | xargs | wc -c" "131072\n" "" "" +X=$(head -c 131066 /dev/zero | tr '\0' x) +# This goes over the kernel's 10 meg limit +testing "big input forces split" \ + 'for i in $(seq 1 100);do echo $X;done|{ xargs >/dev/null && echo yes;}' \ + "yes\n" "" "" + # TODO: what exactly is -x supposed to do? why does coreutils output "one"? #testing "-x" "xargs -x -s 9 || echo expected" "one\nexpected\n" "" "one\ntwo\nthree" diff --git a/toys/posix/xargs.c b/toys/posix/xargs.c index a8ecd4d6..725eb593 100644 --- a/toys/posix/xargs.c +++ b/toys/posix/xargs.c @@ -64,11 +64,10 @@ static char *handle_entries(char *data, char **entry) if (!*s) break; save = ss = s; - // We ought to add sizeof(char *) to TT.bytes to be correct, but we don't - // for bug compatibility with busybox 1.30.1 and findutils 4.7.0. - + // Specifying -s can cause "argument too long" errors. + if (!FLAG(s)) TT.bytes += sizeof(void *)+1; for (;;) { - if (++TT.bytes >= TT.s && TT.s) return save; + if (++TT.bytes >= TT.s) return save; if (!*s || isspace(*s)) break; s++; } @@ -102,8 +101,7 @@ void xargs_main(void) // that the invoked utility has room to modify its environment variables // and command line arguments and still be able to invoke another utility", // though obviously that's not really something you can guarantee. - bytes = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048; - if (!TT.s || TT.s > bytes) TT.s = bytes; + if (!FLAG(s)) TT.s = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048; TT.delim = '\n'*!FLAG(0); @@ -116,7 +114,7 @@ void xargs_main(void) // count entries for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++) - bytes += strlen(toys.optargs[entries]); + bytes += strlen(toys.optargs[entries]) + sizeof(char *)*!FLAG(s); if (bytes >= TT.s) error_exit("argument too long"); // Loop through exec chunks. -- cgit v1.2.3