[Toybox] [landley/toybox] xargs: exec ... Argument list too long (#40)
Rob Landley
rob at landley.net
Wed Aug 10 11:28:58 PDT 2016
On 08/10/2016 07:44 AM, Matthias Urhahn wrote:
> On some Android devices (N5 at 6.0) using a chain of |find .... | xargs
> .... stat ....|, yields the error |Argument list too long|.
>
> Some googlfu shows that this is likely related to the argument exceeding
> the kernels ARG_MAX value.
> Androids ARG_MAX according to this 131072
> <https://github.com/android/platform_bionic/blob/master/libc/kernel/uapi/linux/limits.h>.
The Linux kernel removed that limit in 2007
(https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318
went into the 2.6.22 release).
That said, let's cd to a directory with a lot of files in it:
$ find . | wc
68971 69024 3159459
$ find . | toybox xargs echo
xargs: exec echo: Argument list too long
And I'm seeing a limit here too. Hmmm...
> Manually limiting the xargs argument length using |-s bytes| fixes this
> for me.
The kernel should not be enforcing this? Maybe something else is? There
isn't an obvious ulimit for this... Ah, in include/uapi/linux/limits.h:
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
And that's used in fs/exec.c:
/*
* We've historically supported up to 32 pages (ARG_MAX)
* of argument strings even with small stacks
*/
if (size <= ARG_MAX)
return page;
/*
* Limit to 1/4-th the stack size for the argv+env strings.
* This ensures that:
* - the remaining binfmt code will not run out of stack space,
* - the program will have a reasonable amount of stack left
* to work from.
*/
rlim = current->signal->rlim;
if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
put_page(page);
return NULL;
}
Ok, so that's still there as a MINIMUM, and the maximum is 1/4 the
current stack size ulimit. According to ulimit -s that defaults to 8192
kilobytes (at least on xubuntu 14.04), so 1/4 of 8 megs is 2 megs. And...
$ find . | head -n 40000 | wc
40000 40002 1853620
$ find . | head -n 40000 | toybox xargs echo | wc
1 40002 1853620
Yup, the _actual_ default limit is way more than 131072, and that
default is arbitrarily adjustable even for normal users:
$ ulimit -Hs
unlimited
$ ulimit -s 9999999
$ find . | toybox xargs echo | wc
1 69023 3159436
(Huh, what happens if I set the stack size limit to _less_ than 131072
and then try to exec stuff? Not trying it on my work netbook just now,
thanks...)
> I've looked at the code for xarg in toybox but could not figure out yet
> how the max argument length is determined.
It didn't enforce a default maximum length limit because as far as I
knew the kernel hadn't required one for 9 years. I worked out the math
for enforcing such a limit back when I first did xargs:
http://landley.net/notes-2011.html#17-12-2011
So it's not hard to add a default, but what the default should be isn't
obvious. Back when I noticed the kernel had changed its logic I
_checked_ that I could feed it more than 131072 bytes, and I could, so I
removed the limit. (Not just from xargs, but from find in commit
aa784b09a9fb and possibly elsewhere.)
> Busybox doesn't seem to run into this issue using the same command on
> the same device. Busybox seems to have some sanity checks
> <https://git.busybox.net/busybox/tree/findutils/xargs.c#n529>, adjusting
> the argument length if necessary.
The sanity checks are there (-s is implemented), toybox just doesn't
have a default value if you don't specify one.
> Could there be an issue with how toybox's |xarg| determines the default
> argument length on Android?
See above.
There's a sysconf(_SC_ARG_MAX), which does appear to be calculating this
properly (at least built against glibc, musl is giving me 131072 and I
still haven't got a host bionic toolchain because building bionic
outside of AOSP was nontrivial when I looked at it).
Oh well, use the sysconf and then file a bug against musl. (Elliott will
probably notice this, and if not he'll notice the commit.)
Thanks for the heads up,
Rob
More information about the Toybox
mailing list