Als Programmierer kennen Sie sicherlich den Fehler eines Stapelüberlaufs aufgrund einer offensichtlichen Rekursion. Aber es gibt sicherlich viele seltsame und ungewöhnliche Möglichkeiten, Ihre Lieblingssprache dazu zu bringen, diesen Fehler auszuspucken.
Ziele:
- Muss einen Stapelüberlauf verursachen, der auf der Fehlerausgabe deutlich sichtbar ist.
- Darf keine offensichtliche Rekursion verwenden.
Beispiele für ungültige Programme:
// Invalid, direct obvious recursion.
methodA(){ methodA(); }
// Invalid, indirect, but obvious recursion.
methodA(){ methodB(); }
methodB(){ methodA(); }
Die kreativsten Wege sind die besten, da dies ein Beliebtheitswettbewerb ist . Vermeiden Sie langweilige offensichtliche Antworten wie diese:
throw new StackOverflowError(); // Valid, but very boring and downvote-deserving.
Auch wenn ich jetzt eine Antwort akzeptiert habe, ist das Hinzufügen weiterer Antworten immer noch in Ordnung :)
popularity-contest
stack
masterX244
quelle
quelle
Antworten:
Python
Dies führt dazu, dass der Interpreter sofort ausfällt:
Anstatt eine Rekursion zu verwenden, wird der Stapel nur verkleinert, sodass er sofort überläuft.
quelle
Python
quelle
C / Linux 32bit
Funktioniert durch Überschreiben der Rücksendeadresse. Kehrt also vor dem Anruf
g
zum Punkt in zurück . Funktioniert auf allen Plattformen, auf denen sich Rücksprungadressen auf dem Stapel befinden, jedoch möglicherweise Optimierungen erforderlich sind.main
f
Natürlich ist das Schreiben außerhalb eines Arrays ein undefiniertes Verhalten , und Sie können nicht garantieren, dass es zu einem Stapelüberlauf kommt, anstatt beispielsweise Ihren Schnurrbart blau zu färben. Details der Plattform-, Compiler- und Compiler-Flags können einen großen Unterschied machen.
quelle
JavaScript / DOM
Wenn Sie Ihren Browser beenden möchten, probieren Sie dies in der Konsole aus.
quelle
with (document.body) { addEventListener('DOMSubtreeModified', function() { appendChild(firstChild); }, false); title = 'Kill me!'; } 15:43:43.642 TypeError: can't convert undefined to object
Java
Habe hier irgendwo so etwas gesehen:
Bearbeiten: Gefunden, wo ich es gesehen habe: Joe Ks Antwort auf das kürzeste Programm, das den StackOverflow-Fehler auslöst
Das kann einige Java-Anfänger verwirren. Der rekursive Aufruf wird einfach ausgeblendet.
val + this
wirdval + this.toString()
weilval
ist ein String.Sehen Sie es hier laufen: http://ideone.com/Z0sXiD
quelle
new StringBuilder().append(val).append("").append(this).toString()
, und der letzte Anhang ruft String.valueOf (...) auf, wodurch wiederum String aufgerufen wird. Dies macht Ihren Stack-Trace etwas abwechslungsreicher (drei Methoden stehen zur Verfügung)."" + this.toString()
.+ "" +
könnte Leute hinweisen, da es auf den ersten Blick nutzlos aussieht.String val;
undreturn val + this;
vielleicht etwas hinterhältiger sein""
String-Konstruktion mit einem String zu verknüpfen, mit dem+ ""
C
Ziemlich leicht:
quelle
ulimit -s unlimited
in der Shell löst dies unter Linux)~0u
ist eine ziemlich große Zahl in C.Nicht rekursiver Stapelüberlauf in C
Nicht übereinstimmende Konventionen aufrufen.
Kompilieren mit
gcc -O0
.__cdecl
Funktionen erwarten, dass der Aufrufer den Stapel__stdcall
aufräumt , und erwarten , dass der Angerufene dies tut. Durch Aufrufen des typecast-Funktionszeigers wird die Bereinigung also nie durchgeführt.main
Der Parameter wird bei jedem Aufruf auf den Stapel verschoben, aber es wird kein Popup ausgeführt und schließlich der Stapelfüllungen.quelle
JavaScript
quelle
+this
das?+{toString:"".toLocaleString}
:-)Ich war frustriert darüber, dass Java 7 und Java 8 in meiner vorherigen Antwort gegen meinen bösen Code immun sind . Also entschied ich, dass ein Patch dafür notwendig war.
Erfolg! Ich habe einen
printStackTrace()
Wurf gemachtStackOverflowError
.printStackTrace()
wird häufig zum Debuggen und Protokollieren verwendet, und niemand vermutet, dass dies gefährlich sein könnte. Es ist nicht schwer zu erkennen, dass dieser Code missbraucht werden kann, um einige schwerwiegende Sicherheitsprobleme zu verursachen:Einige Leute denken vielleicht, dass dies eine offensichtliche Rekursion ist. Es ist nicht. Der
EvilException
Konstruktor ruft diegetCause()
Methode nicht auf, sodass eine Ausnahme tatsächlich sicher ausgelöst werden kann. Das Aufrufen dergetCause()
Methode führt auch nicht zu einerStackOverflowError
. Die Rekursion befindet sich innerhalb des normalerweise unerwartetenprintStackTrace()
Verhaltens von JDK und in der Bibliothek von Drittanbietern zum Debuggen und Protokollieren, die zum Untersuchen der Ausnahme verwendet werden. Ferner ist es wahrscheinlich, dass der Ort, an dem die Ausnahme ausgelöst wird, sehr weit von dem Ort entfernt ist, an dem sie behandelt wird.Wie auch immer, hier ist ein Code, der ein wirft
StackOverflowError
und schließlich keine rekursiven Methodenaufrufe enthält. DasStackOverflowError
passiert außerhalb dermain
Methode in JDKsUncaughtExceptionHandler
:quelle
getCause()
Methode führt nicht zuStackOverflowError
. Es beruht auf der Tatsache, dass es einen JDK-Code gibt, der diegetCause()
Methode rekursiv aufruft .getCause
auf "nur" ändern ,return this;
aber anscheinend ist Java dafür zu schlau. Es stellt fest, dass es sich um ein "CIRCULAR REFERENCE
" handelt.StackOverflowError
weil das OpenBSD 5.5-Paket von jdk-1.7.0.21p2v0 einen Fehler hat. Es wirft nichtStackOverflowError
. Es trifftSIGSEGV
und entleert den Kern.Linux x86 NASM-Assembly
Spoiler:
quelle
ret
C ++ zur Kompilierungszeit
Es gibt keine Rekursion dieser Quelldatei, keine der Klassen hat sich selbst als Basisklasse, auch nicht indirekt. (In C ++, in einer Schablonenklasse wie dieser,
S<1>
undS<2>
sind völlig unterschiedliche Klassen.) Der Segmentierungsfehler ist auf einen Stapelüberlauf nach einer Rekursion im Compiler zurückzuführen.quelle
template <typename T> auto foo(T t) -> decltype(foo(t)); decltype(foo(0)) x;
ist etwas kürzer.Bash (Gefahrenalarm)
Streng genommen führt dies nicht direkt zu einem Stapelüberlauf, sondern zu einer Situation , die möglicherweise als " anhaltend stapelüberlauferzeugend " bezeichnet wird: Wenn Sie dies ausführen, bis Ihre Festplatte voll ist, und das Durcheinander mit "rm -rf" beseitigen möchten x ", dieser wird getroffen.
Dies ist jedoch nicht auf allen Systemen der Fall. Einige sind robuster als andere.
Große Gefahr WARNUNG:
Einige Systeme handhaben dies sehr schlecht und es kann schwierig sein, die Daten zu bereinigen (da "rm -rf" selbst auf ein Wiederherstellungsproblem stößt). Möglicherweise müssen Sie ein ähnliches Skript für die Bereinigung schreiben.
Versuchen Sie dies besser in einer Scratch-VM, wenn Sie sich nicht sicher sind.
PS: Gleiches gilt natürlich auch, wenn dies in einem Batch-Skript programmiert oder durchgeführt wird.
PPS: Es kann interessant sein, einen Kommentar von Ihnen zu erhalten, wie sich Ihr bestimmtes System verhält ...
quelle
while cd x; do :; done; cd ..; while rmdir x; cd ..; done;
zu kümmern.Java
Eine schöne von Java Puzzlers . Was wird gedruckt?
Es schlägt tatsächlich mit einem StackOverflowError fehl.
Die Ausnahme im Konstruktor ist nur ein roter Hering. Das sagt das Buch dazu:
quelle
Latex
Der Eingabestapel läuft über, weil er sich
\end
wiederholt in einer Endlosschleife erweitert, wie hier erläutert .TeX schlägt mit a
TeX capacity exceeded, sorry [input stack size=5000]
oder ähnlich fehl .quelle
BF
Wird irgendwann der Stack überlaufen, hängt nur davon ab, wie lange der Interpreter den Stack macht ...
quelle
C #, zur Kompilierungszeit
Es gibt verschiedene Möglichkeiten, den Microsoft C # -Compiler dazu zu bringen, seinen Stapel zu sprengen. Jedes Mal, wenn Sie einen "Ausdruck ist zu komplex zum Kompilieren" -Fehler vom C # -Compiler sehen, der mit ziemlicher Sicherheit darauf zurückzuführen ist, dass der Stack durchgebrannt ist.
Der Parser ist ein rekursiver Abstieg, sodass alle ausreichend tief verschachtelten Sprachstrukturen den Stapel sprengen:
Der Ausdrucksparser ist ziemlich klug, wenn es darum geht, Rekursionen auf der Seite zu eliminieren, auf der häufig Rekursionen auftreten. Gewöhnlich:
die einen enorm tiefen Analysebaum baut, wird den Stapel nicht sprengen. Aber wenn Sie die Rekursion auf der anderen Seite erzwingen:
dann kann der Stapel geblasen werden.
Diese haben die unelegante Eigenschaft, dass das Programm sehr groß ist. Es ist auch möglich, den Semantikanalysator mit einem kleinen Programm in unbegrenzte Rekursionen zu versetzen, da er nicht intelligent genug ist, um bestimmte ungerade Zyklen im Typensystem zu beseitigen. (Roslyn könnte dies verbessern.)
Ich beschreibe hier, warum diese Analyse in eine unendliche Rekursion geht:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx
und für viele weitere interessante Beispiele sollten Sie dieses Papier lesen:
http://research.microsoft.com/en-us/um/people/akenn/generics/FOOL2007.pdf
quelle
fatal error CS1647: An expression is too long or complex to compile near (code)
. Die Dokumentation für diese Fehlermeldung ist hier und genau so, wie Sie sagen: "Es gab einen Stapelüberlauf im Compiler, der Ihren Code verarbeitet."Im Internet (von Milliarden Menschen pro Tag genutzt)
Zum Beispiel auf der Dell Support-Website (keine Beleidigung, sorry Dell):
Wenn Sie das Support-TAG von der URL entfernen, werden unendlich viele Weiterleitungen ausgeführt . In der folgenden URL steht ###### für ein beliebiges Support-TAG.
http://www.dell.com/support/drivers/uk/en/ukdhs1/ServiceTag/#####?s=BSD&~ck=mn
Ich glaube, das entspricht einem Stapelüberlauf.
quelle
/Errors/
, werden der URL einige weitere hinzugefügt, und die Weiterleitungen werden nach dem Empfang von HTTP 400 Bad Request beendet. Dies führt jedoch möglicherweise zu einem besseren Stapelüberlauf als eine unendliche Umleitung.http://www.dell.com/support/drivers/uk/en/ukdhs1/ServiceTag/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/Errors/...
PHP
Ein Stapelüberlauf, der nur mit Schleifenelementen durchgeführt wird.
Erklärung (Hover um den Spoiler zu sehen):
quelle
while (1) { $a = array(&$a); }
oder etwas ähnliches nur die Speichergrenze erreicht ...Java
Ich habe genau das Gegenteil getan - ein Programm, das offensichtlich einen Stapelüberlauffehler auslösen sollte, dies jedoch nicht.
Hinweis: Das Programm wird in O (2 n ) ausgeführt und n ist die Größe des Stapels (normalerweise 1024).
Von Java Puzzlers # 45:
quelle
finally
anstattcatch
, und die Laufzeit ist O (2 ^ n). Antwort aktualisiert.C #
Erster Beitrag, also bitte schont mich.
Dadurch wird einfach ein Stack-Trace erstellt, der oberste Frame (der unser letzter Aufruf ist
Main()
) wird abgerufen, die Methode abgerufen und aufgerufen.quelle
Java
printStackTrace()
in eine Endlosschleife ein.printStackTrace()
wirftStackOverflowError
.Das Verrückte ist, dass es in Java 5 und 6 nicht vom Benutzercode kommt, sondern im JDK-Code. Niemand vernünftiger Verdächtiger,
printStackTrace()
dessen Ausführung gefährlich sein kann.quelle
InnerException
Eigenschaft ist jedoch schreibgeschützt und wird im Konstruktor festgelegt. Daher ist eine Reflektion erforderlich, um dies zu bewirken.JavaScript: Nicht rekursive, iterative Funktionsmutation
Hier gibt es überhaupt keine Rekursion.
f
wird wiederholt mit immer mehr Argumenten versehen, bis der Stack in einem einzigen Funktionsaufruf überlaufen kann . Derconsole.log
Teil ist optional, wenn Sie sehen möchten, wie viele Argumente dafür erforderlich sind. Es sorgt auch dafür, dass clevere JS-Motoren dies nicht wegoptimieren.Code-Golf-Version in CoffeeScript, 28 Zeichen:
quelle
C # mit einem epischen Fehler
Die Art und Weise, wie es fehlschlägt, ist episch und hat mich völlig umgehauen:
Es ist nur ein Bild aus einer scheinbar unendlichen Reihe seltsamer Bilder.
Das muss das Seltsamste sein, was es je gab. Kann jemand erklären? Anscheinend werden diese weißen Blöcke durch die immer größere Anzahl von Leerzeichen angezeigt, die zum Einrücken verwendet werden. Es passiert auf einem Win7 Enterprise x64 mit .NET 4.5.
Ich habe das Ende noch nicht gesehen. Wenn Sie ersetzen
System.Console.Out
mitSystem.IO.Stream.Null
, stirbt es ziemlich schnell.Die Erklärung ist ziemlich einfach. Ich erstelle eine Klasse mit einer einzelnen Eigenschaft und sie gibt immer eine neue Instanz ihres enthaltenden Typs zurück. Es ist also eine unendlich tiefe Objekthierarchie. Jetzt brauchen wir etwas, das versucht, das durchzulesen. Dort verwende ich die
XmlSerializer
, die genau das macht. Und anscheinend verwendet es eine Rekursion.quelle
Bash
Zwar mögen viele erkennen, dass die Rekursion offensichtlich ist , aber es scheint hübsch. Nein?
Bei der Ausführung sehen Sie garantiert:
quelle
_(){_|_;};_
{
, um syntaktisch korrekt zu sein?):(){:|:;}:
Haskell
(traurig, aber wahr, bis zumindest
ghc-7.6
, obwohl mitO1
oder mehr das Problem wegoptimiert wird)quelle
sum
in Bezug auf implementiert wirdfoldl
, die Tail Calls verwendet, aber da der Akku nicht streng ausgewertet wird, wird lediglich ein Stapel von Thunks erzeugt, der so groß ist wie die ursprüngliche Liste. Das Problem verschwindet beim Umschalten auffoldl' (+)
, das streng auswertet und somit eine WHN in seinem Tail Call zurückgibt. Oder, wie gesagt, wenn Sie die Optimierungen von GHC einschalten!Smalltalk
Dies erzeugt eine neue Methode im laufenden Betrieb, die
eine neue Methode im laufenden Betrieb erzeugt, die
eine neue Methode im laufenden Betrieb erzeugt, die
...
...
...
und dann zu ihr überträgt.
Ein zusätzliches Plus an Würze ergibt sich aus der gleichzeitigen Belastung von Stapelspeicher UND Heapspeicher, indem sowohl ein längerer als auch ein längerer Methodenname und eine große Zahl als Empfänger erstellt werden, wenn wir das Loch runterfallen ... (aber die Rekursion trifft uns zuerst ).
kompiliere in Integer:
Dann springen Sie, indem Sie auswerten
"2 downTheRabbitHole"
...... nach einer Weile werden Sie in einem Debugger enden, der eine RecursionException anzeigt.
Dann musst du das ganze Durcheinander beseitigen (sowohl SmallInteger als auch LargeInteger haben jetzt eine Menge Wunderland-Code):
Oder verbringen Sie einige Zeit im Browser und entfernen Sie das Wunderland von Alice.
Hier sind einige aus dem Kopf der Spur:
PS: Die Datei "withoutUpdatingChangesFile:" wurde hinzugefügt, um zu vermeiden, dass die persistente Änderungsprotokolldatei von Smalltalk anschließend bereinigt werden muss.
PPS: Danke für die Herausforderung: Über etwas Neues und Innovatives nachzudenken hat Spaß gemacht!
PPPS: Ich stelle fest, dass einige Smalltalk-Dialekte / -Versionen überlaufende Stack-Frames auf den Heap kopieren. Daher kann es stattdessen zu Speichermangel kommen.
quelle
C #
Wirklich groß
struct
, keine Rekursion, reines C #, kein unsicherer Code.Als Kicker stürzt das Debug-Fenster ab
{Cannot evaluate expression because the current thread is in a stack overflow state.}
Und die generische Version (danke für den Vorschlag NPSF3000)
quelle
C #
Fehlerhafte Implementierung des
==
Operators overriden :Man könnte sagen, es liegt auf der Hand, dass
operator==
sich der==
Operator selbst aufruft , aber normalerweise denken Sie nicht==
so.quelle
Antwort mit SnakeYAML starten
Edit: es ungolfed
Der Leser muss herausfinden, wie das funktioniert: P (Tipp: stackoverflow.com)
Übrigens: Die Rekursion wird dynamisch von SnakeYAML erstellt (Sie werden feststellen, ob Sie wissen, wie es die Felder erkennt, die es serialisiert, und dann hineinschaut)
Point
den Quellcode ).Bearbeiten: erzählen, wie das funktioniert:
SnakeYAML sucht nach einem Paar von
getXXX
undsetXXX
mthod mit demselben Namen fürXXX
und return type des Getters ist derselbe wie parameter of setter; und überraschenderweise hat diePoint
Klasse einPoint getLocation()
undvoid setLocation(Point P)
das kehrt zurück; SnakeYAML merkt es nicht und wiederholt diese Eigenart und StackOverflows. Entdeckt, dass man, wenn man mit ihnen in einem arbeitetHashMap
und auf stackoverflow.com danach fragt.quelle
C #
falsch implementierter Property Getter
quelle
static void Main() { Main(); }
Main()
. Es ist jedoch recht einfach, eine rekursive Eigenschaft versehentlich zu schreiben und dann vom Stapelüberlauf verwechselt zu werden.