[Toybox] [landley/toybox] xargs: exec ... Argument list too long (#40)
enh
enh at google.com
Wed Aug 10 13:08:04 PDT 2016
On Wed, Aug 10, 2016 at 11:28 AM, Rob Landley <rob at landley.net> wrote:
> 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).
yeah, bionic currently just returns ARG_MAX. looks lik glibc divides
the stack by 4 as you describe above.
running
#include <unistd.h>
int main() {
return sysconf(_SC_ARG_MAX)/1024;
}
under strace gets me
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
exit_group(2048) = ?
> 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.)
yeah, this is as good a bionic bug reporting forum as any :-)
> Thanks for the heads up,
>
> Rob
> _______________________________________________
> Toybox mailing list
> Toybox at lists.landley.net
> http://lists.landley.net/listinfo.cgi/toybox-landley.net
--
Elliott Hughes - http://who/enh - http://jessies.org/~enh/
Android native code/tools questions? Mail me/drop by/add me as a reviewer.
More information about the Toybox
mailing list