Wie kommt es zu einem Stapelüberlauf und wie kann am besten sichergestellt werden, dass dies nicht geschieht, oder wie kann dies verhindert werden, insbesondere auf Webservern. Andere Beispiele wären jedoch ebenfalls interessant?
quelle
Wie kommt es zu einem Stapelüberlauf und wie kann am besten sichergestellt werden, dass dies nicht geschieht, oder wie kann dies verhindert werden, insbesondere auf Webservern. Andere Beispiele wären jedoch ebenfalls interessant?
Ein Stapel ist in diesem Zusammenhang der letzte In-First-Out-Puffer, den Sie während der Ausführung Ihres Programms platzieren. Last in, first out (LIFO) bedeutet, dass das Letzte, was Sie eingeben, immer das Erste ist, was Sie wieder herausholen. Wenn Sie 2 Elemente auf den Stapel legen, 'A' und dann 'B', dann das erste, was Sie platzen lassen vom Stapel ist 'B' und das nächste ist 'A'.
Wenn Sie eine Funktion in Ihrem Code aufrufen, wird die nächste Anweisung nach dem Funktionsaufruf auf dem Stapel gespeichert und der durch den Funktionsaufruf möglicherweise überschriebene Speicherplatz. Die von Ihnen aufgerufene Funktion verbraucht möglicherweise mehr Stapel für ihre eigenen lokalen Variablen. Wenn dies erledigt ist, wird der verwendete lokale variable Stapelspeicher freigegeben und die vorherige Funktion wiederhergestellt.
Ein Stapelüberlauf liegt vor, wenn Sie mehr Speicher für den Stapel verbraucht haben, als Ihr Programm verwenden sollte. In eingebetteten Systemen haben Sie möglicherweise nur 256 Bytes für den Stapel, und wenn jede Funktion 32 Bytes belegt, können Sie nur Funktionsaufrufe 8 tief haben - Funktion 1 ruft Funktion 2 auf, die Funktion 3 aufruft, die Funktion 4 aufruft .... wer aufruft Funktion 8, die Funktion 9 aufruft, aber Funktion 9 den Speicher außerhalb des Stapels überschreibt. Dies kann Speicher, Code usw. überschreiben.
Viele Programmierer machen diesen Fehler, indem sie die Funktion A aufrufen, die dann die Funktion B aufruft, die dann die Funktion C aufruft und dann die Funktion A aufruft. Dies funktioniert möglicherweise die meiste Zeit, aber nur einmal führt die falsche Eingabe dazu, dass sie für immer in diesem Kreis bleibt bis der Computer erkennt, dass der Stapel überblasen ist.
Rekursive Funktionen sind ebenfalls eine Ursache dafür. Wenn Sie jedoch rekursiv schreiben (dh Ihre Funktion ruft sich selbst auf), müssen Sie sich dessen bewusst sein und statische / globale Variablen verwenden, um eine unendliche Rekursion zu verhindern.
Im Allgemeinen verwalten das Betriebssystem und die Programmiersprache, die Sie verwenden, den Stapel, und es liegt nicht in Ihrer Hand. Sie sollten sich Ihr Aufrufdiagramm ansehen (eine Baumstruktur, die von Ihrem Hauptbild aus anzeigt, was jede Funktion aufruft), um zu sehen, wie tief Ihre Funktionsaufrufe gehen, und um Zyklen und Rekursionen zu erkennen, die nicht beabsichtigt sind. Absichtliche Zyklen und Rekursionen müssen künstlich überprüft werden, um Fehler zu vermeiden, wenn sie sich zu oft gegenseitig aufrufen.
Abgesehen von guten Programmierpraktiken, statischen und dynamischen Tests können Sie auf diesen High-Level-Systemen nicht viel tun.
In der eingebetteten Welt, insbesondere im Code für hohe Zuverlässigkeit (Automobil, Flugzeug, Weltraum), führen Sie umfangreiche Codeüberprüfungen und -prüfungen durch, aber Sie führen auch Folgendes aus:
Aber in Hochsprachen laufen auf Betriebssystemen:
Es hängt von der 'Sandbox' ab, ob Sie den Stapel steuern oder sogar sehen können. Die Chancen stehen gut, dass Sie Webserver wie jede andere Hochsprache und jedes andere Betriebssystem behandeln können - es liegt größtenteils nicht in Ihren Händen, aber überprüfen Sie die Sprache und den Serverstapel, die Sie verwenden. Es ist beispielsweise möglich, den Stapel auf Ihrem SQL Server zu sprengen.
-Adam
Ein Stapelüberlauf in echtem Code tritt sehr selten auf. Die meisten Situationen, in denen es auftritt, sind Rekursionen, bei denen die Beendigung vergessen wurde. Es kann jedoch selten in stark verschachtelten Strukturen auftreten, z. B. in besonders großen XML-Dokumenten. Die einzige wirkliche Hilfe besteht darin, den Code so umzugestalten, dass anstelle des Aufrufstapels ein explizites Stapelobjekt verwendet wird.
Die meisten Leute werden Ihnen sagen, dass ein Stapelüberlauf bei einer Rekursion ohne Exit-Pfad auftritt. Wenn Sie jedoch mit ausreichend großen Datenstrukturen arbeiten, hilft Ihnen selbst ein korrekter Rekursions-Exit-Pfad nicht weiter.
Einige Optionen in diesem Fall:
Ein Stapelüberlauf tritt auf, wenn Jeff und Joel der Welt einen besseren Ort bieten möchten, um Antworten auf technische Fragen zu erhalten. Es ist zu spät, um diesen Stapelüberlauf zu verhindern. Diese "andere Seite" hätte es verhindern können, indem sie nicht verschwommen war. ;)
Unendliche Rekursion ist ein häufiger Weg, um einen Stapelüberlauffehler zu erhalten. Um zu verhindern - immer sicher, es gibt einen Ausgang Weg, wird getroffen werden. :-)
Eine andere Möglichkeit, einen Stapelüberlauf zu erzielen (zumindest in C / C ++), besteht darin, eine enorme Variable auf dem Stapel zu deklarieren.
char hugeArray[100000000];
Das wird es tun.
Normalerweise ist ein Stapelüberlauf das Ergebnis eines unendlichen rekursiven Aufrufs (angesichts der heutzutage bei Standardcomputern üblichen Speichermenge).
Wenn Sie eine Methode, Funktion oder Prozedur aufrufen, besteht die "Standard" -Methode oder der Aufruf aus:
In der Regel dauert dies einige Bytes, abhängig von der Anzahl und dem Typ der Parameter sowie der Maschinenarchitektur.
Sie werden dann sehen, dass der Stapel wächst, wenn Sie rekursive Aufrufe tätigen. Jetzt wird der Stapel normalerweise so im Speicher reserviert, dass er entgegengesetzt zum Heap wächst. Bei einer großen Anzahl von Aufrufen ohne "Zurückkommen" beginnt der Stapel voll zu werden.
In früheren Zeiten kann es einfach zu einem Stapelüberlauf kommen, weil Sie einfach den gesamten verfügbaren Speicher ausgelaugt haben. Bei dem virtuellen Speichermodell (bis zu 4 GB auf einem X86-System), das außerhalb des Gültigkeitsbereichs lag, suchen Sie normalerweise nach einem unendlichen rekursiven Aufruf, wenn ein Stapelüberlauffehler auftritt.
quelle
Was? Niemand liebt diejenigen, die von einer Endlosschleife umgeben sind?
quelle
Abgesehen von der Form des Stapelüberlaufs, die Sie durch eine direkte Rekursion erhalten (z. B.
Fibonacci(1000000)
), ist eine subtilere Form davon, die ich oft erlebt habe, eine indirekte Rekursion, bei der eine Funktion eine andere Funktion aufruft, die eine andere aufruft, und dann eine von Diese Funktionen rufen den ersten erneut auf.Dies kann häufig bei Funktionen auftreten, die als Reaktion auf Ereignisse aufgerufen werden, aber selbst neue Ereignisse erzeugen können, z.
In diesem Fall kann der Aufruf von
ResizeWindow
dazu führen, dass derWindowSizeChanged()
Rückruf erneut ausgelöst wird, wodurchResizeWindow
erneut aufgerufen wird, bis Ihnen der Stapel ausgeht. In solchen Situationen müssen Sie häufig die Reaktion auf das Ereignis verschieben, bis der Stapelrahmen zurückgekehrt ist, z. B. durch Senden einer Nachricht.quelle
In Anbetracht dessen, dass dies mit "Hacking" gekennzeichnet war, vermute ich, dass der "Stapelüberlauf", auf den er sich bezieht, eher ein Aufrufstapelüberlauf als ein Stapelüberlauf auf höherer Ebene ist, wie in den meisten anderen Antworten hier angegeben. Es gilt nicht wirklich für verwaltete oder interpretierte Umgebungen wie .NET, Java, Python, Perl, PHP usw., in denen normalerweise Webanwendungen geschrieben sind. Ihr einziges Risiko ist also der Webserver selbst, in den wahrscheinlich geschrieben wird C oder C ++.
Schauen Sie sich diesen Thread an:
/programming/7308/what-is-a-good-starting-point-for-learning-buffer-overflow
quelle
Ich habe das Stapelüberlaufproblem neu erstellt, während ich die häufigste Fibonacci-Zahl erhalten habe, dh 1, 1, 2, 3, 5 ..... also Berechnung für fib (1) = 1 oder fib (3) = 2 .. fib (n ) = ??.
Nehmen wir für n an, wir werden interessiert sein - was ist, wenn n = 100.000 ist, was ist dann die entsprechende Fibonacci-Zahl?
Der Ein-Schleifen-Ansatz ist wie folgt:
das ganz einfach und Ergebnis ist -
Ein anderer Ansatz, den ich angewendet habe, ist Divide and Concur per Rekursion
dh Fib (n) = fib (n-1) + Fib (n-2) und dann weitere Rekursion für n-1 & n-2 ..... bis 2 & 1. programmiert als -
Wenn ich den Code für n = 100.000 ausgeführt habe, ist das Ergebnis wie folgt:
Oben sehen Sie, dass der StackOverflowError erstellt wurde. Der Grund dafür ist zu viele Rekursionen als -
Jeder Eintrag im Stapel erstellt also 2 weitere Einträge und so weiter ... was dargestellt wird als -
Schließlich werden so viele Einträge erstellt, dass das System den Stapel nicht verarbeiten kann und StackOverflowError ausgelöst wird.
Zur Vorbeugung: Für die obige Beispielperspektive - 1. Vermeiden Sie die Verwendung des Rekursionsansatzes oder reduzieren / begrenzen Sie die Rekursion erneut um eine Ebenenteilung, z. B. wenn n zu groß ist, und teilen Sie dann das n, damit das System mit seiner Grenze umgehen kann. 2. Verwenden Sie einen anderen Ansatz, wie den Loop-Ansatz, den ich im ersten Codebeispiel verwendet habe. (Ich beabsichtige überhaupt nicht, Divide & Concur oder Recursion zu verschlechtern, da dies legendäre Ansätze in vielen der bekanntesten Algorithmen sind. Meine Absicht ist es, die Rekursion zu begrenzen oder von ihr fernzuhalten, wenn ich Probleme mit dem Stapelüberlauf vermute.)
quelle