Como linux-2.6.23 ARG_MAX
não é necessariamente uma constante predeterminada, o tamanho total dos argumentos pode ser de até 1/4 do tamanho da pilha (veja ulimit -s
, tamanho da pilha em kB; mas /proc/1/limits
é mais definitivo). No entanto, ARG_MAX
não é apenas para os argumentos do processo, ele também contém as variáveis de ambiente, que você pode precisar levar em conta.
POSIX define o que ARG_MAX
significa e um limite inferior aceitável ( _POSIX_ARG_MAX
4096). Seu valor estático é (historicamente) disponível através de um #define
nos cabeçalhos do sistema, e também é definido nos cabeçalhos do kernel do Linux. Seu valor efetivo está disponível em sysconf()
ou getconf ARG_MAX
na linha de comando.
Se você verificar os cabeçalhos da glibc ( sys/param.h
), verá isto:
/* The kernel headers defines ARG_MAX. The value is wrong, though. */
#ifdef __undef_ARG_MAX
# undef ARG_MAX
# undef __undef_ARG_MAX
#endif
Isso é de glibc-2.17, isso apareceu por volta de 2.11 (2009), primeiro suporte para essas datas para 2.8 (2008), mas anterior a 2.14 (2011) houve um erro na lógica acima que impediu que funcionasse como esperado. A intenção é garantir que ARG_MAX
seja indefinido, se não for uma constante, portanto, os programas devem contar com sysconf()
. (Mesmo que seja definido, pode ser apenas um limite inferior garantido, e os programas devem usar sysconf()
para determinar os limites superiores da variável, veja sysconf(3)
)
Você pode verificar o que seu compilador C vê com ( gcc
, bash
/ zsh
somente sintaxe):
$ gcc -E -dM -x c <(echo "#include <sys/param.h>") | fgrep ARG
#define ARG_MAX 131072
#define NCARGS ARG_MAX
#define _POSIX_ARG_MAX 4096
A saída acima é de um sistema antigo (2.6.27), que possui suporte ao kernel, mas não o tempo de execução completo (suporte a glibc). Se você não vir nenhuma linha ARG_MAX
, então não é um limite pré-determinado, e você deve usar (sysconf) getconf ARG_MAX
:
$ getconf ARG_MAX
2097152
Uma maneira útil de verificar o suporte também é:
$ xargs --show-limits < /dev/null
Your environment variables take up 2542 bytes
POSIX upper limit on argument length (this system): 2092562
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2090020
Size of command buffer we are actually using: 131072
Isso é de um sistema linux-2.6.37 / glib-2.13 com os limites mais altos. Observe a linha final de saída, xargs
defaults (tempo de compilação) para um limite "sensato", provavelmente no caso de algum dos processos iniciados não serem capazes de manipular valores muito grandes. Você pode modificar isso em tempo de execução com a opção -s
. Além disso, se você tiver um ulimit -s
em vigor, esses números podem ser menores. Este deve funcionar corretamente desde findutils-4.3.9 (2007). Veja também: link
Para verificar o perl:
% perl -MPOSIX -e 'print ARG_MAX . "\n"';
131072
O texto acima é novamente de um sistema antigo, um novo sistema deve mostrar:
% perl -MPOSIX -e 'print ARG_MAX . "\n"';
Your vendor has not defined POSIX macro ARG_MAX, used at -e line 1
Para resumir:
- Se você estiver executando um kernel pós-2.6.23, o kernel permitirá que tamanhos maiores sejam passados ao criar um processo. Esta é uma condição necessária, mas não suficiente .
- O processo pai não deve impor nenhum limite de tempo de execução incorreto (por exemplo, com
ARG_MAX
codificado), ele deve verificar os códigos de erroexec()
E2BIG
e deve usarsysconf(_SC_ARG_MAX)
se necessário - O processo filho não deve aplicar nenhum limite de tempo de execução incorreto, em particular seu código de inicialização que processa os parâmetros fornecidos do kernel não deve ter limites codificados incorretos (por exemplo, ao configurar
argc
,argc
, a área de ambiente tempo de uso). Isso é feito tipicamente em libc (glibc). - Para pai e filho, você também pode precisar configurar e construir suporte de tempo a partir da libc (ou equivalente). Para glibc isso requer pelo menos o glibc-2.8 (embora deva ser possível contorná-lo, pode não ser simples ou limpo)
Uma combinação de problemas é um kernel atualizado (linux > = 2.6.23), mas falta ou suspeita de suporte a glibc (glibc < = 2.14)
Se você estiver executando um kernel antigo, primeiro certifique-se de que seu fornecedor não tenha feito o back-port do recurso. Caso contrário, você pode, em princípio, alterar o limite do kernel e recompilar, mas você pode precisar também modificar pelo menos alguns cabeçalhos do sistema ou código-fonte para suporte ao trabalho.
Os programas devem ser capazes de manipular valores arbitrários, mas isso nem sempre é o caso: link
Applications should not assume any particular value for a limit. [...] It should be noted, however, that many of the listed limits are not invariant, and at runtime, the value of the limit may differ from those given in this header, for the following reasons:
- The limit is pathname-dependent.
- The limit differs between the compile and runtime machines.
For these reasons, an application may use the fpathconf(), pathconf(), and sysconf() functions to determine the actual value of a limit at runtime.