Was ist die maximale Größe eines Umgebungsvariablenwerts?

82

Gibt es eine Begrenzung für die Datenmenge, die in einer Umgebungsvariablen unter Linux gespeichert werden kann, und wenn ja: Was ist das?

Für Windows habe ich folgenden KB-Artikel gefunden, der Folgendes zusammenfasst: Windows XP oder höher: 8191 Zeichen Windows 2000 / NT 4.0: 2047 Zeichen

Gio
quelle
Die tatsächliche Grenze für Windows liegt bei 31.767. Sie lesen über den setBefehl, dessen Befehlszeilenlimit auf 8191 Zeichen begrenzt ist. Siehe diesen msdn-Artikel. Trotzdem eine zufällige Einschränkung.
Christopher Currens
5
8191 ist nicht so zufällig. Es ist 2 ^ 13 - 1.
Barnaby Dawson
AWS Lambda: Die Gesamtgröße des Satzes [von Umgebungsvariablen] überschreitet nicht 4 KB ( Quelle )
Martin Thoma
1
@BarnabyDawson vielleicht meinte Christopher es in dem Sinne, dass es willkürlich war?
0xC0000022L

Antworten:

74

Ich glaube nicht, dass es unter Linux ein Umgebungsvariablenlimit gibt. Die Gesamtgröße aller Umgebungsvariablen zusammen ist zeitlich begrenzt execve(). Weitere Informationen finden Sie hier unter "Beschränkungen der Größe von Argumenten und der Umgebung" .

Ein Prozess kann die Umgebung über den von exec zugewiesenen anfänglichen Speicherplatz hinaus verwenden setenv()oder erweitern putenv().

Hier ist ein schnelles und schmutziges Programm, das eine Umgebungsvariable mit 256 MB erstellt.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    size_t size = 1 << 28; /* 256 MB */
    char *var;

    var = malloc(size);
    if (var == NULL) {
        perror("malloc");
        return 1;
    }

    memset(var, 'X', size);
    var[size - 1] = '\0';
    var[0] = 'A';
    var[1] = '=';

    if (putenv(var) != 0) {
        perror("putenv");
        return 1;
    }

/*  Demonstrate E2BIG failure explained by paxdiablo */
    execl("/bin/true", "true", (char *)NULL);
    perror("execl");   


    printf("A=%s\n", getenv("A"));

    return 0;
}
Sigjuice
quelle
5
+1 für die execve () Info. Sie können Umgebungsvariablen bis zu (mindestens) 8 Millionen hinzufügen, aber exec () -Aufrufe funktionieren nicht. Dies äußert sich in bash als "Argumentliste ist zu lang", wenn Sie dann versuchen, einen Befehl auszuführen.
Paxdiablo
1
Beachten Sie auch, dass POSIX erfordert, dass ARG_MAX mindestens _POSIX_ARG_MAX ist, was 4096 sein sollte.
ninjalj
10
Die Top-Antwort (von Chipaca) auf askUbuntu beschreibt die Verwendung xargs --show-limits, um weitere Informationen zu erhalten.
DocSalvager
Ich sehe auch das Limit pro Argumentzeichenfolge - "Zusätzlich beträgt das Limit pro Zeichenfolge 32 Seiten (die Kernelkonstante MAX_ARG_STRLEN)"
kiran01bm
23

Nun, es ist mindestens 4M auf meiner Box. Zu diesem Zeitpunkt langweilte ich mich und ging davon. Hoffentlich ist die Terminalausgabe fertig, bevor ich am Montag wieder bei der Arbeit bin :-)

export b1=A
export b2=$b1$b1
export b4=$b2$b2
export b8=$b4$b4
export b16=$b8$b8
export b32=$b16$b16
export b64=$b32$b32
export b128=$b64$b64
export b256=$b128$b128
export b512=$b256$b256
export b1k=$b512$b512
export b2k=$b1k$b1k
export b4k=$b2k$b2k
export b8k=$b4k$b4k
export b16k=$b8k$b8k
export b32k=$b16k$b16k
export b64k=$b32k$b32k
export b128k=$b64k$b64k
export b256k=$b128k$b128k
export b512k=$b256k$b256k
export b1m=$b512k$b512k
export b2m=$b1m$b1m
export b4m=$b2m$b2m
echo $b4m
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
:    :    :    :    :    :    :    :    :    :    :    :
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Wenn Sie befürchten, dass 4M für Ihre Umgebungsvariable nicht ausreicht, sollten Sie Ihre Arbeitsweise überdenken.

Vielleicht wäre es eine bessere Idee, die Informationen in eine Datei einzufügen und dann eine Umgebungsvariable zu verwenden, um auf diese Datei zu verweisen. Ich habe Fälle gesehen, in denen die Variable, wenn sie vom Formular ist @/path/to/any/fspec, die tatsächlichen Informationen aus der Datei erhält path/to/any/fspec. Wenn es nicht funktioniert mit beginnen @, verwendet es den Wert der Umgebungsvariablen selbst.


Interessanterweise beschwert sich bei jedem dieser Variablen jeder einzelne Befehl darüber, dass die Argumentliste zu lang ist. Obwohl Sie sie festlegen können, kann er möglicherweise keine Programme starten, nachdem Sie dies getan haben (da dies erforderlich ist) Weitergabe der Umgebung an diese Programme).

paxdiablo
quelle
1
Ich hoffe, Sie haben ein Skript verwendet und dies nicht alles von Hand eingegeben!
Chris Huang-Leaver
2
Nein, daher das bisschen "Langeweile". Die Befehlszeilenbearbeitung im Vi-Modus hat es ein wenig einfacher gemacht, aber ich dachte, es könnte fehlschlagen, bevor ich die 4M-Marke erreicht habe. So ist das Leben.
Paxdiablo
1
Aber warum stoppen ksh-Variablen bei 256 KB ? Möglicherweise CentOS auch
phuclv
@ LưuVĩnhPhúc: weil Programme Grenzen haben. Sie können willkürliche Grenzen sein oder auf verfügbaren Ressourcen basieren, aber die Grenzen existieren. Möglicherweise nahm DavidK an, dass seine Muschel nicht von Verrückten (falsch) benutzt werden würde, die es besser wissen sollten :-)
paxdiablo
7

Ich habe einen kurzen Test auf meiner Linux-Box mit dem folgenden Snippet durchgeführt:

a="1"
while true
do
    a=$a$a
    echo "$(date) $(numfmt --to=iec-i --suffix=B --padding=7 ${#a})" 
done

Auf meiner Box (Gentoo 3.17.8-gentoo-r1) ergibt dies (letzte Ausgabezeilen):

Wed Jan  3 12:16:10 CET 2018   16MiB
Wed Jan  3 12:16:11 CET 2018   32MiB
Wed Jan  3 12:16:12 CET 2018   64MiB
Wed Jan  3 12:16:15 CET 2018  128MiB
Wed Jan  3 12:16:21 CET 2018  256MiB
Wed Jan  3 12:16:33 CET 2018  512MiB
xrealloc: cannot allocate 18446744071562068096 bytes

Also: das Limit ist ziemlich hoch!

Cyberbird
quelle
1
18446744071562068096 Bytes sind ungefähr 15 Exabyte. :) Das scheint ein großer Sprung von 512MiB zu sein.
Marcus
1
@Marcus: es ist ... Ich denke, dass irgendwie 1 GB, dh 1073741824 Bytes, dh 2 ^ 30 Bytes, irgendwo überlaufen. Die Anzahl der Bytes im Fehler 18446744071562068096 liegt ziemlich nahe bei 2 ^ 64, dh 18446744073709551616
Cyberbird
1
Ich habe begrenzte C / gdb-Kenntnisse, aber ich denke, das Problem liegt in der Bash-Quelldatei subst.c Die Funktion sub_append_string (Zeile 726) verwendet eine vorzeichenbehaftete int-Variable namens n, um die neue Größe zu berechnen. Die neue Größe (2 ^ 31) würde passen, aber es gibt eine Ausrichtungsberechnung: n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); und ich vermute das Teil: (n + DEFAULT_ARRAY_SIZE)Überläufe. Alles sehr schön, aber wir sind hier natürlich weit über jede vernünftige Grenze hinaus.
Cyberbird
3

Hier sind zwei hilfreiche Befehle:

  • getconf -a |grep MAX

  • true | xargs --show-limits

dmitry_podyachev
quelle
Welche der ~ 100 Variablen ist relevant? Wo sind sie dokumentiert?
ingomueller.net
1

Ich weiß es nicht genau, aber ein kurzes Experiment zeigt, dass kein Fehler auftritt, z. B. bei 64 KB Wert:

% perl -e 'print "#include <stdlib.h>\nint main() { return setenv(\"FOO\", \"", "x"x65536, "\", 1); }\n";'\
| gcc -x c -o envtest - && ./envtest && echo $?
0
laalto
quelle
1

Ich habe diesen sehr schnellen und schmutzigen PHP-Code (unten) verwendet, ihn für verschiedene Werte geändert und festgestellt, dass er für variable Längen bis zu 128 KB funktioniert. Danach funktioniert es aus irgendeinem Grund nicht mehr. Es wird keine Ausnahme ausgelöst, es wird kein Fehler gemeldet, aber der Wert wird nicht in der Unterschale angezeigt.

Vielleicht ist dies eine PHP-spezifische Grenze? Vielleicht gibt es php.ini-Einstellungen, die sich darauf auswirken könnten? Oder gibt es eine Begrenzung für die Größe von Vars, die eine Subshell erben wird? Möglicherweise gibt es relevante Kernel- oder Shell-Konfigurationseinstellungen.

Standardmäßig scheint in CentOS das Limit für das Festlegen einer Variable in der Umgebung über putenv in PHP bei 128 KB zu liegen.

<?php

  $s = 'abcdefghijklmnop';
  $s2 = "";
  for ($i = 0; $i < 8100; $i++) $s2 .= $s;
  $result = putenv('FOO='.$s2);
  print shell_exec('echo \'FOO: \'${FOO}');
  print "length of s2: ".strlen($s2)."\n";
  print "result = $result\n";
?>

Versions Information -

[root@localhost scratch]# php --version
PHP 5.2.6 (cli) (built: Dec  2 2008 16:32:08) 
<..snip..>

[root@localhost scratch]# uname -a
Linux localhost.localdomain 2.6.18-128.2.1.el5 #1 SMP Tue Jul 14 06:36:37 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

[root@localhost scratch]# cat /etc/redhat-release 
CentOS release 5.3 (Final)
Shavais
quelle
0

Die Befehlszeile (mit allen Argumenten) und die Umgebungsvariable sollten kleiner als 128 KB sein.

J-16 SDiZ
quelle
11
Zitieren erforderlich
rr-