Reserviert das Betriebssystem die festgelegte Menge des gültigen virtuellen Speicherplatzes für den Stapel oder etwas anderes? Kann ich einen Stapelüberlauf nur mit großen lokalen Variablen erzeugen?
Ich habe ein kleines C
Programm geschrieben, um meine Vermutung zu testen. Es läuft auf X86-64 CentOS 6.5.
#include <string.h>
#include <stdio.h>
int main()
{
int n = 10240 * 1024;
char a[n];
memset(a, 'x', n);
printf("%x\n%x\n", &a[0], &a[n-1]);
getchar();
return 0;
}
Das Ausführen des Programms gibt &a[0] = f0ceabe0
und&a[n-1] = f16eabdf
Die Proc Maps zeigen den Stack: 7ffff0cea000-7ffff16ec000. (10248 * 1024B)
Dann habe ich versucht zu erhöhen n = 11240 * 1024
Das Ausführen des Programms gibt &a[0] = b6b36690
und&a[n-1] = b763068f
Die Proc Maps zeigen den Stack: 7fffb6b35000-7fffb7633000. (11256 * 1024B)
ulimit -s
druckt 10240
in meinem PC.
Wie Sie sehen, ist in beiden Fällen der Stapel größer als der angegebene ulimit -s
. Und der Stapel wächst mit einer größeren lokalen Variablen. Die Oberseite des Stapels ist irgendwie 3-5kB mehr entfernt &a[0]
(AFAIK die rote Zone ist 128B).
Wie wird diese Stapelzuordnung zugewiesen?
quelle
ulimit -s
10240 versucht , wie unter den Bedingungen des OP, und ich erhalte erwartungsgemäß ein SIGSEGV (dies ist erforderlich für POSIX: "Wenn dieses Limit überschritten wird, soll SIGSEGV für den Thread generiert werden. "). Ich vermute einen Fehler im OP-Kernel.Linux-Kernel 4.2
rlim[RLIMIT_STACK]
, was dem POSIX entsprichtgerlimit(RLIMIT_STACK)
acct_stack_growth
Minimales Testprogramm
Wir können es dann mit einem minimalen NASM 64-Bit-Programm testen:
Stellen Sie sicher, dass Sie ASLR deaktivieren und Umgebungsvariablen entfernen, da diese auf dem Stapel abgelegt werden und Speicherplatz belegen:
Das Limit liegt irgendwo etwas unter meinem
ulimit -s
(8MiB für mich). Dies liegt an den zusätzlichen System V-Daten, die anfänglich zusätzlich zur Umgebung auf dem Stapel abgelegt wurden: Linux 64-Befehlszeilenparameter in Assembly | PaketüberflussWenn Sie dies ernst meinen, erstellen Sie mit TODO ein minimales initrd-Image , das vom Stapel nach oben und unten geschrieben wird, und führen Sie es dann mit QEMU + GDB aus . Setzen Sie ein
dprintf
auf die Schleife, die die Stapeladresse und einen Haltepunkt bei drucktacct_stack_growth
. Es wird herrlich sein.Verbunden:
quelle
Standardmäßig ist die maximale Stapelgröße auf 8 MB pro Prozess konfiguriert.
Sie kann jedoch folgendermaßen geändert werden
ulimit
:Den Standard in kB anzeigen:
Auf unbegrenzt setzen:
ulimit -s unlimited
Auswirkungen auf die aktuelle Shell und Subshells und ihre untergeordneten Prozesse.
(
ulimit
ist ein Shell-Builtin-Befehl)Sie können den tatsächlichen Stapeladressbereich anzeigen, der verwendet wird mit:
cat /proc/$PID/maps | grep -F '[stack]'
unter Linux.
quelle
ulimit -s
KB für das Programm gültig. In meinem Fall ist es 10240 KB. Aber wenn ich ein lokales Array deklarierechar a[10240*1024]
und setzea[0]=1
, wird das Programm korrekt beendet. Warum?int n = 10240*1024; char a[n]; memset(a,'x',n);
... seg Fehler.a[]
wurde @amos in Ihrem 10-MB-Stack nicht zugeordnet. Der Compiler hat möglicherweise festgestellt, dass es keinen rekursiven Aufruf gab und hat eine spezielle Zuordnung vorgenommen, oder etwas anderes wie einen diskontinuierlichen Stapel oder eine Indirektion.