GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Was definiert die maximale Größe für ein einzelnes Befehlsargument?

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:

  1. Ist das Verhalten richtig oder gibt es irgendwo einen Fehler?
  2. Wenn nicht, ist dieses Verhalten irgendwo dokumentiert? Gibt es einen anderen Parameter, der das Maximum für ein einzelnes Argument definiert?
  3. Ist dieses Verhalten auf Linux beschränkt (oder sogar auf bestimmte Versionen davon)?
  4. 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

  1. Definitiv kein Fehler.
  2. Der Parameter, der die maximale Größe für ein Argument definiert, ist MAX_ARG_STRLEN . Außer den Kommentaren in binfmts.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.

  3. 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.

  4. 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 der execve erstellt werden Systemaufruf, wenn er möglicherweise immer noch ein E2BIG zurückgibt Fehler an den aufrufenden Prozess (obwohl Zeiger auf jeden argv 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).

Verwandte:Was ist der Unterschied zwischen Semikolon und doppeltem kaufmännischem Und &&?

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 mit sh -c in Makefiles einbettete – http://www.mail-archive.com/[email protected]/msg05522.html

Linux
  1. Wie groß darf der Wert einer Linux-Umgebungsvariablen maximal sein?

  2. Wie finde ich die maximale Stapelgröße?

  3. Was ist das Äquivalent zum Linux-Dateibefehl für Windows?

  4. Was ist die Standardgrößeneinheit im Linux-Befehl ls -l?

  5. Was macht ein „Feld“ für den Schnittbefehl aus?

8 Tipps für die Linux-Kommandozeile

Was ist der Linux-Überwachungsbefehl + Beispiele

Benötigen Sie das „eingebaute“ Eingebaute?

Was ist der Kill-Befehl in Linux?

was ist der zuverlässigste befehl, um die tatsächliche größe einer datei zu finden linux

Wozu dient die Option -o im Befehl useradd?