Search code examples
clinuxposix

system() function string length limit


How long can be a string passed to system()?

I know the POSIX minimum is 4096, but I would like to know the actual size I can use. Is there any macro defined in any header for that, similar to FILENAME_MAX?

char cmd[SOME_MACRO];

...
system(cmd);

Solution

  • system exec's a shell with arguments "sh","-c", YourAgumentToSystem, (char*)0 (guaranteed by POSIX), so the maximum length (not counting the '\0' terminator) is ARG_MAX -1 -3 -3 - size_of_your_environment.

    ARG_MAX is defined in limits.h as

    "Maximum length of argument to the exec functions including environment data."

    If limits.h, doesn't define ARG_MAX, you should be able to call sysconf(_SC_ARG_MAX) to obtain a runtime limit.

    The linux manpage for execve (called by system) provides more information:

    On Linux prior to kernel 2.6.23, the memory used to store the environment and argument strings was limited to 32 pages (defined by the kernel constant MAX_ARG_PAGES). On architectures with a 4-kB page size, this yields a maximum size of 128 kB.

    On kernel 2.6.23 and later, most architectures support a size limit derived from the soft RLIMIT_STACK resource limit (see getrlimit(2)) that is in force at the time of the execve() call. (Architectures with no memory management unit are excepted: they maintain the limit that was in effect before kernel 2.6.23.) This change allows programs to have a much larger argument and/or environment list. For these architectures, the total size is limited to 1/4 of the allowed stack size. (Imposing the 1/4-limit ensures that the new program always has some stack space.) Since Linux 2.6.25, the kernel places a floor of 32 pages on this size limit, so that, even when RLIMIT_STACK is set very low, applications are guaranteed to have at least as much argument and environment space as was provided by Linux 2.6.23 and earlier. (This guarantee was not provided in Linux 2.6.23 and 2.6.24.) Additionally, the limit per string is 32 pages (the kernel constant MAX_ARG_STRLEN), and the maximum number of strings is 0x7FFFFFFF.

    To measure the size of your environment, you can run:

    extern char **environ;
    size_t envsz = 0; for(char **e=environ; *e; e++) envsz += strlen(*e)+1;
    

    (As Zan Lynx has pointed out in the comments, this can be sped up (cca 20 times as per my measurements—from 1600ns to 80ns for the 100-string 6KB environment I had when measuring) if you assume the char* pointers in environ point to a contiguous buffer, which they do after a program starts, but calls to setenv, putenv, or unsetenv typically break this:

    extern char **environ;
    char **e; for(e=environ; *e; e++) {}
    size_t envsz =  ($_sz)(e[-1]+strlen(e[-1])+1 - *environ);
    

    In any case, the speed up at the cost of robustness shouldn't matter much if you're expecting to fork+exec (/system) soon, given that fork+exec typically costs at least around 1-2ms on Linux on a modern machine.)