Ich hatte den Eindruck, dass hier nicht die maximale Länge eines einzelnen Arguments das Problem war, sondern die Gesamtgröße des gesamten Argumentarrays plus die Größe der Umgebung, die auf ARG_MAX
begrenzt ist . Daher dachte ich, dass so etwas wie das Folgende gelingen würde:
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
Mit dem - 100
Dies ist mehr als genug, um den Unterschied zwischen der Größe der Umgebung in der Shell und dem echo
zu berücksichtigen Prozess. Stattdessen bekam ich den Fehler:
bash: /bin/echo: Argument list too long
Nachdem ich eine Weile herumgespielt hatte, stellte ich fest, dass das Maximum eine ganze Hex-Größenordnung kleiner war:
/bin/echo
$(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1)))
>/dev/null
Wenn das Minuszeichen entfernt wird, kehrt der Fehler zurück. Scheinbar ist das Maximum für ein einzelnes Argument tatsächlich ARG_MAX/16
und die -1
berücksichtigt das Nullbyte, das am Ende der Zeichenfolge im Argumentarray platziert wird.
Ein weiteres Problem ist, dass, wenn das Argument wiederholt wird, die Gesamtgröße des Argumentarrays näher bei ARG_MAX
liegen kann , aber immer noch nicht ganz da:
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
Verwenden von "${args[0]:6533}"
macht hier das letzte Argument 1 Byte länger und gibt die Argument list too long
Error. Es ist unwahrscheinlich, dass dieser Unterschied durch die Größe der gegebenen Umgebung erklärt wird:
$ cat /proc/$$/environ | wc -c
1045
Fragen:
- Ist das Verhalten richtig oder gibt es irgendwo einen Fehler?
- Wenn nicht, ist dieses Verhalten irgendwo dokumentiert? Gibt es einen anderen Parameter, der das Maximum für ein einzelnes Argument definiert?
- Ist dieses Verhalten auf Linux beschränkt (oder sogar auf bestimmte Versionen davon)?
- Was erklärt die zusätzliche Diskrepanz von ~5 KB zwischen der tatsächlichen maximalen Größe des Argumentarrays plus der ungefähren Größe der Umgebung und
ARG_MAX
?
Zusätzliche Informationen:
uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux
Akzeptierte Antwort:
Antworten
- Definitiv kein Fehler.
-
Der Parameter, der die maximale Größe für ein Argument definiert, ist
MAX_ARG_STRLEN
. Außer den Kommentaren inbinfmts.h
gibt es für diesen Parameter keine Dokumentation :/* * 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
Wie gezeigt wird, hat Linux auch eine (sehr große) Begrenzung der Anzahl von Argumenten für einen Befehl.
-
Eine Begrenzung der Größe eines einzelnen Arguments (die sich von der Gesamtbegrenzung für Argumente plus Umgebung unterscheidet) scheint spezifisch für Linux zu sein. Dieser Artikel gibt einen detaillierten Vergleich von
ARG_MAX
und Äquivalente auf Unix-ähnlichen Systemen.MAX_ARG_STRLEN
wird für Linux diskutiert, aber es wird kein Äquivalent auf anderen Systemen erwähnt.Der obige Artikel besagt auch, dass
MAX_ARG_STRLEN
wurde in Linux 2.6.23 eingeführt, zusammen mit einer Reihe anderer Änderungen in Bezug auf die Maximalwerte für Befehlsargumente (siehe unten). Das Log/Diff für den Commit finden Sie hier. -
Es ist immer noch nicht klar, was die zusätzliche Diskrepanz zwischen dem Ergebnis von
getconf ARG_MAX
erklärt und die tatsächlich maximal mögliche Größe von Argumenten plus Umgebung. Die verwandte Antwort von Stephane Chazelas legt nahe, dass ein Teil des Speicherplatzes durch Zeiger auf jede der Argument-/Umgebungszeichenfolgen belegt wird. Meine eigene Untersuchung legt jedoch nahe, dass diese Zeiger nicht früh in derexecve
erstellt werden Systemaufruf, wenn er möglicherweise immer noch einE2BIG
zurückgibt Fehler an den aufrufenden Prozess (obwohl Zeiger auf jedenargv
string werden sicherlich später erstellt).Außerdem sind die Zeichenfolgen im Speicher, soweit ich sehen kann, zusammenhängend, sodass hier keine Speicherlücken aufgrund der Ausrichtung entstehen. Obwohl es sehr wahrscheinlich ein Faktor in allem ist, was macht den zusätzlichen Speicher aufbrauchen. Zu verstehen, was den zusätzlichen Speicherplatz verwendet, erfordert ein detaillierteres Wissen darüber, wie der Kernel Speicher zuweist (was ein nützliches Wissen ist, also werde ich es später untersuchen und aktualisieren).
ARG_MAX Verwirrung
Seit Linux 2.6.23 (als Ergebnis dieses Commit) gab es Änderungen an der Art und Weise, wie Maximalwerte für Befehlsargumente gehandhabt werden, was Linux von anderen Unix-ähnlichen Systemen unterscheidet. Zusätzlich zum Hinzufügen von MAX_ARG_STRLEN
und MAX_ARG_STRINGS
, das Ergebnis von getconf ARG_MAX
hängt jetzt von der Stapelgröße ab und kann sich von ARG_MAX
unterscheiden in limits.h
.
Normalerweise das Ergebnis von getconf ARG_MAX
wird 1/4
sein der Stapelgröße. Betrachten Sie Folgendes in bash
mit ulimit
um die Stapelgröße zu erhalten:
$ echo $(( $(ulimit -s)*1024 / 4 )) # ulimit output in KiB
2097152
$ getconf ARG_MAX
2097152
Das obige Verhalten wurde jedoch durch diesen Commit (hinzugefügt in Linux 2.6.25-rc4~121) leicht geändert. ARG_MAX
in limits.h
dient jetzt als harte Untergrenze für das Ergebnis von getconf ARG_MAX
. Wenn die Stapelgröße so eingestellt ist, dass 1/4
der Stapelgröße ist kleiner als ARG_MAX
in limits.h
, dann die limits.h
Wert wird verwendet:
$ 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
Beachten Sie auch, dass, wenn die Stack-Größe kleiner als die minimal mögliche ARG_MAX
eingestellt wird , dann die Größe des Stapels (RLIMIT_STACK
) wird zur Obergrenze der Argument-/Umgebungsgröße vor E2BIG
zurückgegeben (obwohl getconf ARG_MAX
wird weiterhin den Wert in limits.h
anzeigen ).
Eine letzte Anmerkung ist, dass, wenn der Kernel ohne CONFIG_MMU
gebaut wird (Unterstützung für Speicherverwaltungshardware), dann die Überprüfung von ARG_MAX
ist deaktiviert, daher gilt das Limit nicht. Obwohl MAX_ARG_STRLEN
und MAX_ARG_STRINGS
gelten immer noch.
Weiterführende Literatur
- Verwandte Antwort von Stephane Chazelas – https://unix.stackexchange.com/a/110301/48083
- In einer detaillierten Seite, die die meisten der oben genannten Punkte abdeckt. Enthält eine Tabelle von
ARG_MAX
(und äquivalente) Werte auf anderen Unix-ähnlichen Systemen – http://www.in-ulm.de/~mascheck/various/argmax/ - Scheinbar die Einführung von
MAX_ARG_STRLEN
verursachte einen Bug in Automake, der Shell-Skripte mitsh -c
in Makefiles einbettete – http://www.mail-archive.com/[email protected]/msg05522.html