Tenía la impresión de que la longitud máxima de un solo argumento no era el problema aquí, sino el tamaño total de la matriz de argumentos general más el tamaño del entorno, que está limitado a ARG_MAX
. Por lo tanto, pensé que algo como lo siguiente tendría éxito:
env_size=$(cat /proc/$$/environ | wc -c)
(( arg_size = $(getconf ARG_MAX) - $env_size - 100 ))
/bin/echo $(tr -dc [:alnum:] </dev/urandom | head -c $arg_size) >/dev/null
Con el - 100
siendo más que suficiente para dar cuenta de la diferencia entre el tamaño del entorno en el shell y el echo
proceso. En su lugar, recibí el error:
bash: /bin/echo: Argument list too long
Después de jugar un rato, descubrí que el máximo era un orden de magnitud hexadecimal completo más pequeño:
/bin/echo
$(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1)))
>/dev/null
Cuando se elimina el menos uno, vuelve el error. Aparentemente, el máximo para un solo argumento es en realidad ARG_MAX/16
y el -1
da cuenta del byte nulo colocado al final de la cadena en la matriz de argumentos.
Otro problema es que cuando se repite el argumento, el tamaño total de la matriz de argumentos puede estar más cerca de ARG_MAX
, pero todavía no del todo:
args=( $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) )
for x in {1..14}; do
args+=( ${args[0]} )
done
/bin/echo "${args[@]}" "${args[0]:6534}" >/dev/null
Usando "${args[0]:6533}"
aquí hace que el último argumento sea 1 byte más largo y hace que la Argument list too long
error. Es poco probable que esta diferencia se deba al tamaño del entorno dado:
$ cat /proc/$$/environ | wc -c
1045
Preguntas:
- ¿Es correcto este comportamiento o hay un error en alguna parte?
- Si no es así, ¿este comportamiento está documentado en alguna parte? ¿Hay otro parámetro que defina el máximo para un solo argumento?
- ¿Este comportamiento se limita a Linux (o incluso a versiones particulares de este)?
- ¿Qué explica la discrepancia adicional de ~5 KB entre el tamaño máximo real de la matriz de argumentos más el tamaño aproximado del entorno y
ARG_MAX
?
Información adicional:
uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux
Respuesta aceptada:
Respuestas
- Definitivamente no es un error.
-
El parámetro que define el tamaño máximo para un argumento es
MAX_ARG_STRLEN
. No hay documentación para este parámetro aparte de los comentarios enbinfmts.h
:/* * These are the maximum length and maximum number of strings passed to the * execve() system call. MAX_ARG_STRLEN is essentially random but serves to * prevent the kernel from being unduly impacted by misaddressed pointers. * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. */ #define MAX_ARG_STRLEN (PAGE_SIZE * 32) #define MAX_ARG_STRINGS 0x7FFFFFFF
Como se muestra, Linux también tiene un límite (muy grande) en la cantidad de argumentos para un comando.
-
Un límite en el tamaño de un único argumento (que difiere del límite general de argumentos más el entorno) parece ser específico de Linux. Este artículo ofrece una comparación detallada de
ARG_MAX
y equivalentes en sistemas similares a Unix.MAX_ARG_STRLEN
se discute para Linux, pero no se menciona ningún equivalente en ningún otro sistema.El artículo anterior también establece que
MAX_ARG_STRLEN
se introdujo en Linux 2.6.23, junto con una serie de otros cambios relacionados con los máximos de argumentos de comando (discutidos a continuación). El registro/diff para la confirmación se puede encontrar aquí. -
Todavía no está claro qué explica la discrepancia adicional entre el resultado de
getconf ARG_MAX
y el tamaño máximo posible real de los argumentos más el entorno. La respuesta relacionada de Stephane Chazelas sugiere que parte del espacio está representado por punteros a cada una de las cadenas de argumento/entorno. Sin embargo, mi propia investigación sugiere que estos punteros no se crean al principio delexecve
llamada al sistema cuando aún puede devolver unE2BIG
error en el proceso de llamada (aunque los punteros a cadaargv
ciertamente se crean más tarde).Además, las cadenas son contiguas en la memoria hasta donde puedo ver, por lo que no hay espacios de memoria debidos a la alineación aquí. Aunque es muy probable que sea un factor dentro de lo que hace utilizar la memoria adicional. Entender qué usa el espacio extra requiere un conocimiento más detallado de cómo el kernel asigna la memoria (que es un conocimiento útil, por lo que investigaré y actualizaré más adelante).
ARG_MAX Confusión
Desde Linux 2.6.23 (como resultado de este compromiso), ha habido cambios en la forma en que se manejan los máximos de argumentos de comando, lo que hace que Linux sea diferente de otros sistemas similares a Unix. Además de agregar MAX_ARG_STRLEN
y MAX_ARG_STRINGS
, el resultado de getconf ARG_MAX
ahora depende del tamaño de la pila y puede ser diferente de ARG_MAX
en limits.h
.
Normalmente el resultado de getconf ARG_MAX
será 1/4
del tamaño de la pila. Considere lo siguiente en bash
usando ulimit
para obtener el tamaño de la pila:
$ echo $(( $(ulimit -s)*1024 / 4 )) # ulimit output in KiB
2097152
$ getconf ARG_MAX
2097152
Sin embargo, el comportamiento anterior cambió ligeramente con esta confirmación (agregada en Linux 2.6.25-rc4~121). ARG_MAX
en limits.h
ahora sirve como un límite inferior estricto en el resultado de getconf ARG_MAX
. Si el tamaño de la pila se establece de forma que 1/4
del tamaño de la pila es menor que ARG_MAX
en limits.h
, luego limits.h
se utilizará el valor:
$ grep ARG_MAX /usr/include/linux/limits.h
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
$ ulimit -s 256
$ echo $(( $(ulimit -s)*1024 / 4 ))
65536
$ getconf ARG_MAX
131072
Tenga en cuenta también que si el tamaño de la pila se establece por debajo del mínimo posible ARG_MAX
, luego el tamaño de la pila (RLIMIT_STACK
) se convierte en el límite superior del tamaño del argumento/entorno antes de E2BIG
se devuelve (aunque getconf ARG_MAX
seguirá mostrando el valor en limits.h
).
Una última cosa a tener en cuenta es que si el núcleo se construye sin CONFIG_MMU
(soporte para hardware de administración de memoria), luego la verificación de ARG_MAX
está deshabilitado, por lo que el límite no se aplica. Aunque MAX_ARG_STRLEN
y MAX_ARG_STRINGS
todavía aplica.
Lecturas adicionales
- Respuesta relacionada de Stephane Chazelas:https://unix.stackexchange.com/a/110301/48083
- En una página detallada que cubre la mayor parte de lo anterior. Incluye una tabla de
ARG_MAX
(y equivalentes) valores en otros sistemas similares a Unix:http://www.in-ulm.de/~mascheck/various/argmax/ - Al parecer, la introducción de
MAX_ARG_STRLEN
causó un error con Automake que estaba incrustando scripts de shell en Makefiles usandosh -c
– http://www.mail-archive.com/[email protected]/msg05522.html