La forma más extraña de producir un desbordamiento de pila [cerrado]

146

Como programador, ciertamente conoce el error de un desbordamiento de pila debido a una recurrencia obvia. Pero ciertamente hay muchas formas extrañas e inusuales de hacer que su idioma favorito escupe ese error.

Objetivos:

  1. Debe provocar un desbordamiento de pila que sea claramente visible en la salida de error.
  2. No se permite usar una recurrencia obvia.

Ejemplos de programas inválidos:

// Invalid, direct obvious recursion.
methodA(){ methodA(); }
// Invalid, indirect, but obvious recursion.
methodA(){ methodB(); }
methodB(){ methodA(); }

Las formas más creativas son las mejores, ya que este es un . Es decir, evite respuestas obvias aburridas como esta:

throw new StackOverflowError(); // Valid, but very boring and downvote-deserving.

Aunque acepté una respuesta ahora, agregar más respuestas todavía está bien :)

masterX244
fuente
14
Tiendo a producir navegando a stackoverflow.com, aunque se me conoce por consultar 'desbordamiento de pila' en mi motor de búsqueda de elección.
OJFord
21
Utiliza Internet Explorer. Una forma segura de atrapar uno :)
asgoth
64
La forma más extraña de producir un desbordamiento de pila es publicar un concurso de popularidad en codegolf.stackexchange.com pidiendo a las personas que publiquen la forma más extraña de producir un desbordamiento de pila. Los respondedores, al probar sus soluciones a la pregunta, producirán un desbordamiento de pila. Sin embargo, no lo he probado, así que no puedo estar seguro de que funcione (por eso no lo publiqué como respuesta).
Tim Seguine
3
Soy parcial a este método: joelonsoftware.com/items/2008/09/15.html
robert
11
Conducir un Toyota (Hey, espera un minuto, mi coche es un Toyota ...)
quebrantahuesos aprensivos

Respuestas:

224

Pitón

import sys
sys.setrecursionlimit(1)

Esto hará que el intérprete falle inmediatamente:

$ cat test.py
import sys
sys.setrecursionlimit(1)
$ python test.py
Exception RuntimeError: 'maximum recursion depth exceeded' in <function _remove at 0x10e947b18> ignored
Exception RuntimeError: 'maximum recursion depth exceeded' in <function _remove at 0x10e8f6050> ignored
$ 

En lugar de usar la recursividad, simplemente reduce la pila para que se desborde inmediatamente.

marinus
fuente
12
Lindo, pero no exactamente a lo que apuntaba la pregunta original en mi opinión.
Nit
12
@Nit No veo el problema. ¿Qué pasa con esta solución no es satisfactoria?
SimonT
17
@ masterX244 Sí, el punto central de la pregunta es "no lo hagas de la manera habitual".
Plutor
24
@Plutor, ¿suele configurar un StackOverFlow a propósito?
Kiwy
15
Esto fue solo ligeramente inteligente la primera vez que se publicó .
primo
189

Pitón

import webbrowser
webbrowser.open("http://stackoverflow.com/")
TheDoctor
fuente
77
Fantástico. Agradable y elegante
James Webster
103
Mucho literal. Muy respuesta
Tim Seguine
47
Bueno, esto muestra un desbordamiento de pila, pero para producir uno, esto solo funciona si es Jeff Atwood o Joel Spolsky ejecutándolo.
Caracol mecánico
10
@TimSeguine Wow.
Sean Allred
99
No es una respuesta ya que no está en la salida de error.
Pierre Arlaud
131

C / Linux 32bit

void g(void *p){
        void *a[1];
        a[2]=p-5;
}
void f(){
        void *a[1];
        g(a[2]);
}
main(){
        f();
        return 0;
}

Funciona sobrescribiendo la dirección de retorno, por lo que gvuelve al punto mainantes de llamar f. Funcionará para cualquier plataforma donde las direcciones de retorno estén en la pila, pero puede requerir ajustes.

Por supuesto, escribir fuera de una matriz es un comportamiento indefinido , y no tiene garantía de que cause un desbordamiento de la pila en lugar de, por ejemplo, pintar el bigote de azul. Los detalles de la plataforma, el compilador y los indicadores de compilación pueden marcar una gran diferencia.

Ugoren
fuente
1
¿No produciría esto un segfault?
11684
44
¡+1 por la extraña manipulación de la pila y absolutamente sin recurrencia!
RSFalcon7
66
@ 11684, es un comportamiento indefinido, por lo que en general podría fallar. En Linux de 32 bits (que probé), escribe fuera de la matriz, sobrescribe la dirección de retorno y no se bloquea hasta que la pila se desborda.
ugoren
46
"Pinta tu bigote de azul" -> Esa línea me tenía.
Aneesh Dogra
2
Guau. Esto está fantásticamente ofuscado.
MirroredFate
108

JavaScript / DOM

with (document.body) {
    addEventListener('DOMSubtreeModified', function() {
        appendChild(firstChild);
    }, false);

    title = 'Kill me!';
}

Si quieres matar tu navegador, prueba eso en la consola.

Visión
fuente
53
Estoy seguro de que mereces más +1 votos, pero lamentablemente la gente intentó esto antes de votar ... jajaja
Reactgular
55
Bueno, eso fue efectivo. Ni siquiera podía abrir mi administrador de tareas para matarlo.
primo
1
Use Chrome, cierre la pestaña. Problema resuelto.
Cole Johnson
1
with (document.body) { addEventListener('DOMSubtreeModified', function() { appendChild(firstChild); }, false); title = 'Kill me!'; } 15:43:43.642 TypeError: can't convert undefined to object
Brian Minton
1
Damn My Firefox fue ahorcado
Farhad
91

Java

Vi algo como esto en algún lugar por aquí:

Editar: Encontrado donde lo vi: la respuesta de Joe K al programa más corto que arroja StackOverflow Error

public class A {
    String val;
    public String toString() {
        return val + this;
    }

    public static void main(String[] args) {
        System.out.println(new A());
    }
}

Eso puede confundir a algunos principiantes de Java. Simplemente oculta la llamada recursiva. val + thisse convierte en val + this.toString()porque vales una cadena.

Véalo correr aquí: http://ideone.com/Z0sXiD

Justin
fuente
30
En realidad, sí new StringBuilder().append(val).append("").append(this).toString(), y el último anexo llama a String.valueOf (...), que a su vez llama a String. Esto hace que el seguimiento de su pila sea un poco variado (tres métodos allí).
Paŭlo Ebermann
2
@ PaŭloEbermann Sí, eso es correcto. Sin embargo, es mucho más fácil decir que se vuelve "" + this.toString().
Justin
2
Creo que + "" +podría alertar a la gente, ya que parece inútil a primera vista. String val;y return val + this;podría ser ligeramente más astuto
Cruncher
@Cruncher en absoluto. Si usted es un codificador de Java, sabría que la manera fácil de concatenar un int a una cadena durante la ""construcción de -String es con el+ ""
Justin
55
En una aplicación del mundo real, preferiría evitar la recursión infinita y los errores de desbordamiento de pila
jon_darkstar
77

C

Muy fácil:

int main()
{
    int large[10000000] = {0};
    return 0;
}
Shahbaz
fuente
10
+1 para no obvio! A pesar de que depende mucho del sistema (un ulimit -s unlimiteden el shell resuelve esto en Linux)
RSFalcon7
44
@ RSFalcon7, gracias por el +1, ¡pero para mí esto fue realmente lo más obvio!
Shahbaz
14
@Cruncher: no produce recursión. El problema dado fue volar la pila. En muchos sistemas operativos, la pila es de tamaño fijo y mucho más pequeña que diez millones de pulgadas, por lo que esto hace volar la pila.
Eric Lippert
2
@HannoBinder, en Linux donde probé, no obtienes un error de desbordamiento de pila. Obtiene un error de segmentación, ya que desbordar la pila da como resultado el acceso a segmentos no propietarios. No estoy seguro de si el error de desbordamiento de pila incluso existe en Linux, ya que una llamada de función recursiva infinita también produce una falla de segmentación.
Shahbaz
3
~0ues un número bastante grande en C.
Vortico
63

Desbordamiento de pila no recursivo en C

La convención de llamada no coincide.

typedef void __stdcall (* ptr) (int);

void __cdecl hello (int x) { }

void main () {
  ptr goodbye = (ptr)&hello;
  while (1) 
    goodbye(0);
}

Compilar con gcc -O0.

__cdecllas funciones esperan que la persona que llama limpie la pila, y __stdcallespera que la persona que llama lo haga, por lo que al llamar a través del puntero de la función de conversión de texto, la limpieza nunca se realiza: mainempuja el parámetro a la pila para cada llamada, pero nada aparece y finalmente la pila se llena

Jason C
fuente
2
buena forma de enviar spam a la pila: P
masterX244
62

JavaScript

window.toString = String.toLocaleString;
+this;
Ryan Cavanaugh
fuente
55
Este es subestimado.
Ry-
1
¿Qué +thishacer?
NobleUplift
8
Unary + invoca la operación abstracta ToNumber. Que utiliza la operación ToPrimitive con un tipo de pista de número. ToPrimitive en un objeto utiliza el método interno [[DefaultValue]], que cuando pasa una pista de número, primero verifica si el método valueOf () existe y devuelve una primitiva. window.valueOf () devuelve un objeto, por lo que en su lugar [[DefaultValue]] devuelve el resultado de llamar a ToString (). Lo primero que hace window.toString (ahora que es toLocaleString) es invocar toString en 'this'. Repetir.
Ryan Cavanaugh
3
Si Chrome arroja un error, 'Demasiada recurrencia', entonces funciona en Chrome, ¿verdad? La pila se desborda, y así es como Chrome ofrece una excepción de desbordamiento de pila.
David Conrad
44
Deberías usar +{toString:"".toLocaleString}:-)
Bergi
62

Estaba frustrado por el hecho de que Java 7 y Java 8 son inmunes a mi código maligno en mi respuesta anterior . Entonces decidí que era necesario un parche para eso.

¡Éxito! Hice printStackTrace()tirar a StackOverflowError. printStackTrace()se usa comúnmente para depurar y registrar y nadie sospecha razonablemente que podría ser peligroso. No es difícil ver que se puede abusar de este código para crear algunos problemas de seguridad graves:

public class StillMoreEvilThanMyPreviousOne {
    public static void main(String[] args) {
        try {
            evilMethod();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void evilMethod() throws Exception {
        throw new EvilException();
    }

    public static class EvilException extends Exception {
        @Override
        public Throwable getCause() {
            return new EvilException();
        }
    }
}

Algunas personas pueden pensar que esta es una recurrencia obvia. No lo es. El EvilExceptionconstructor no llama al getCause()método, por lo que, después de todo, esa excepción se puede lanzar de manera segura. Llamar al getCause()método no dará como resultado StackOverflowErrortampoco. La recursión está dentro del printStackTrace()comportamiento normalmente insospechado de JDK y de cualquier biblioteca de terceros para la depuración y el registro que se utilizan para inspeccionar la excepción. Además, es probable que el lugar donde se produce la excepción esté muy lejos del lugar donde se maneja.

De todos modos, aquí hay un código que arroja un StackOverflowErrory no contiene llamadas a métodos recursivos después de todo. Lo que StackOverflowErrorocurre fuera del mainmétodo, en JDK's UncaughtExceptionHandler:

public class StillMoreEvilThanMyPreviousOneVersion2 {
    public static void main(String[] args) {
        evilMethod();
    }

    private static void evilMethod() {
        throw new EvilException();
    }

    public static class EvilException extends RuntimeException {
        @Override
        public Throwable getCause() {
            return new EvilException();
        }
    }
}
Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"
Victor Stafusa
fuente
2
: D y ahora con un método compatible con stackoverflow cross java version. ¡Bastardo malvado! : D
Kiwy
99
Me inclino a considerar obvia la recursividad en este caso.
Taemyr
1
@BlacklightShining Llamar al getCause()método no da como resultado StackOverflowError. Se basa en el hecho de que hay un código de JDK que llama recursivamente al getCause()método.
Victor Stafusa
2
Pensé que podría simplificar esto cambiando el cuerpo de getCausesolo return this;pero aparentemente Java es demasiado inteligente para eso. Se da cuenta de que es un " CIRCULAR REFERENCE".
David Conrad
1
No obtuve un StackOverflowErrorporque el paquete OpenBSD 5.5 de jdk-1.7.0.21p2v0 tiene un error. No tira StackOverflowError. Golpea SIGSEGVy descarga el núcleo.
Kernigh
57

Ensamblaje NASM Linux x86

section .data
    helloStr:     db 'Hello world!',10 ; Define our string
    helloStrLen:  equ $-helloStr       ; Define the length of our string

section .text
    global _start

    doExit:
        mov eax,1 ; Exit is syscall 1
        mov ebx,0 ; Exit status for success
        int 80h   ; Execute syscall

    printHello:
        mov eax,4           ; Write syscall is No. 4
        mov ebx,1           ; File descriptor 1, stdout
        mov ecx,helloStr    ; Our hello string
        mov edx,helloStrLen ; The length of our hello string
        int 80h             ; execute the syscall

    _start:
        call printHello ; Print "Hello World!" once
        call doExit     ; Exit afterwards

Revelación:

Olvidando regresar de printHello, entonces saltamos directamente a _start nuevamente.

Michael Ehrenreich
fuente
78
En asamblea, nada es obvio.
11684
21
@ 11684: Creo que lo contrario es cierto: en el ensamblaje, todo es obvio porque nadie puede usar abstracciones para ocultar lo que su código realmente está haciendo.
Mason Wheeler
3
Esto es brillante por su simplicidad y elegancia.
haneefmubarak
11
@MasonWheeler: Prefiero decir que todo es visible en lugar de obvio ... Para una buena manera de ver la diferencia entre visible y obvio, me encanta referirme a underhanded.xcott.com
Olivier Dulac
2
Recuerdo mis frecuentes errores de olvidoret
Ruslan
48

C ++ en tiempo de compilación

template <unsigned N>
struct S : S<N-1> {};

template <>
struct S<0> {};

template
struct S<-1>;
$ g ++ -c test.cc -ftemplate-depth = 40000
g ++: error interno del compilador: falla de segmentación (programa cc1plus)
Por favor envíe un informe de error completo,
con fuente preprocesada si corresponde.
Consulte para obtener instrucciones.

No hay recurrencia en este archivo fuente, ninguna de las clases se tiene como clase base, ni siquiera indirectamente. (En C ++, en una clase de plantilla como esta, S<1>y S<2>son clases completamente distintas.) El error de segmentación se debe al desbordamiento de la pila después de la recursión en el compilador.

hvd
fuente
77
Confieso que habría llamado a esto una recurrencia obvia en su metaprograma.
2
GCC detecta la recursividad y se detiene con gracia de este lado (4.8 y superior parecen estar bien)
Alec Teal
2
template <typename T> auto foo(T t) -> decltype(foo(t)); decltype(foo(0)) x;Es un poco más corto.
Casey
2
@hvd Parece estar explotando un error en GCC. clang detecta el uso erróneo , que supongo que ya conoce, pero hace que mi GCC arroje casi 2 megabytes de mensajes de error.
Casey
44
+1 para desbordamiento de meta stack : p
Aschratt
45

Bash (alerta de peligro)

while true
do 
  mkdir x
  cd x
done

Estrictamente hablando, eso no apilará directamente el desbordamiento, sino que generará lo que se puede etiquetar como " una situación persistente de generación de apilamiento por flujo ": cuando ejecuta esto hasta que su disco esté lleno y desea eliminar el desorden con "rm -rf x ", ese es golpeado.

Sin embargo, no sucede en todos los sistemas. Algunos son más robustos que otros.

Gran peligro ADVERTENCIA:

algunos sistemas manejan esto muy mal y es posible que tenga dificultades para limpiar (porque "rm -rf" en sí mismo se encontrará con un problema de recusión). Puede que tenga que escribir un script similar para la limpieza.

Mejor intente esto en una VM virtual si no está seguro.

PD: lo mismo se aplica, por supuesto, si se programa o se realiza en un script por lotes.
PPS: puede ser interesante recibir un comentario de usted, cómo se comporta su sistema particular ...

blabla999
fuente
como escribí: en muchos sistemas, rm -rf intenta fallar y es golpeado por uno (tal vez ya no, en estos días, con un espacio de direcciones de 64 bits, pero puede que en máquinas más pequeñas con una pila más pequeña). Por supuesto, también puede haber -implementations "RM" alrededor, que lo hacen de manera diferente ...
blabla999
2
Me parece que algo así while cd x; do :; done; cd ..; while rmdir x; cd ..; done;debería encargarse de esto.
Blacklight Shining
Tienes toda la razón (eso es lo que quise decir con "script similar para la limpieza"). Sin embargo, una vez que su disco (o cuota) está lleno, incluso puede tener dificultades para iniciar sesión después, ya que algunos sistemas solían lidiar mal con esa situación. Tendrá que ingresar como root y hacer el script (que es fácil en las PC de hoy en día, pero a menudo era difícil en la antigüedad, cuando las computadoras eran utilizadas por más de un usuario).
blabla999
divertido, esto obtiene más votos que la magia Smalltalk a continuación (¡nunca pensé eso!)
blabla999
Alguien intentó esto en Windows?
Sarge Borsch
43

Java

Una buena de Java Puzzlers . ¿Qué imprime?

public class Reluctant {
    private Reluctant internalInstance = new Reluctant();

    public Reluctant() throws Exception {
        throw new Exception("I'm not coming out");
    }

    public static void main(String[] args) {
        try {
            Reluctant b = new Reluctant();
            System.out.println("Surprise!");
        } catch (Exception ex) {
            System.out.println("I told you so");
        }
    }
}

Realmente falla con un StackOverflowError.

La excepción en el constructor es solo un arenque rojo. Esto es lo que el libro tiene que decir al respecto:

Cuando invoca un constructor, los inicializadores de variable de instancia se ejecutan antes que el cuerpo del constructor . En este caso, el inicializador de la variable internalInstanceinvoca al constructor de forma recursiva. Ese constructor, a su vez, inicializa su propio internalInstancecampo invocando nuevamente al constructor Renuente y así sucesivamente, hasta el infinito. Estas invocaciones recursivas provocan que StackOverflowErrorel cuerpo del constructor tenga la oportunidad de ejecutarse. Debido a que StackOverflowErrores un subtipo en Errorlugar de Exception, la cláusula catch mainno lo atrapa.

ntoskrnl
fuente
41

Látex

\end\end

La pila de entrada se desborda porque \endse expande repetidamente en un bucle infinito, como se explica aquí .

TeX falla con una TeX capacity exceeded, sorry [input stack size=5000]o similar.

bwDraco
fuente
1
Estaba esperando un problema de TeX / LaTeX. Esas cosas son más discordantes que la mayoría; por lo general, me he olvidado de que lo que estoy haciendo cuenta como programación cuando de repente me las arreglé para escribir algo que es infinitamente recursivo.
Ernir
1
Consulte también codegolf.stackexchange.com/questions/9359/…
bwDraco el
1
"Se ha excedido la capacidad de TeX, lo siento" TeX es muy educado cuando falla.
Alex A.
40

BF

Eventualmente desbordará la pila, solo depende de cuánto tiempo el intérprete hace la pila ...

+[>+]
Timtech
fuente
55
Ese código me recuerda al juego de la vida.
Adam Arold
10
Estrictamente hablando, no hay pila en brainfuck.
fejesjoco
66
@fejesjoco Tape, si lo desea.
Timtech
32

C #, en tiempo de compilación

Hay varias formas de hacer que el compilador de Microsoft C # explote su pila; cada vez que vea un error de "expresión es demasiado complejo para compilar" desde el compilador de C #, es casi seguro que la pila ha explotado.

El analizador es un descenso recursivo, por lo que cualquier estructura de lenguaje suficientemente anidada volará la pila:

 class C { class C { class C { ....

El analizador de expresiones es bastante inteligente para eliminar las recursiones en el lado que comúnmente se recurre. Generalmente:

x = 1 + 1 + 1 + 1 + .... + 1;

que construye un árbol de análisis enormemente profundo, no volará la pila. Pero si obligas a que ocurra la recursión en el otro lado:

x = 1 + (1 + (1 + (1 + ....+ (1 + 1))))))))))))))))))))))))))))))))))))))))))...;

entonces la pila se puede volar.

Estos tienen la propiedad poco elegante de que el programa es muy grande. También es posible hacer que el analizador semántico entre recurrencias ilimitadas con un pequeño programa porque no es lo suficientemente inteligente como para eliminar ciertos ciclos extraños en el sistema de tipos. (Roslyn podría mejorar esto).

public interface IN<in U> {}
public interface IC<X> : IN<IN<IC<IC<X>>>> {}
...
IC<double> bar = whatever;
IN<IC<string>> foo = bar;  // Is this assignment legal? 

Describo por qué este análisis entra en una recursión infinita aquí:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx

y para muchos más ejemplos interesantes deberías leer este artículo:

http://research.microsoft.com/en-us/um/people/akenn/generics/FOOL2007.pdf

Eric Lippert
fuente
2
El mensaje de error exacto es fatal error CS1647: An expression is too long or complex to compile near (code). La documentación para este mensaje de error está aquí , y es exactamente como usted dice: "Hubo un desbordamiento de pila en el compilador que procesaba su código".
bwDraco
32

En Internet (utilizado por miles de millones de personas / día)

Redirects, HTTP status code: 301

Por ejemplo, en el sitio web de asistencia de Dell (sin ofender, lo siento, Dell):

Si elimina el TAG de soporte de la URL, se redirige infinitamente . En la siguiente URL, ###### es cualquier TAG de soporte.

http://www.dell.com/support/drivers/uk/en/ukdhs1/ServiceTag/######?s=BSD&~ck=mn

Creo que es equivalente a un desbordamiento de pila.

codeSetter
fuente
55
buena manera :) Firefox dice que redirige, por lo que la solicitud no se puede resolver, que es el equivalente de stackoverflow :)
masterX244
3
Tenga en cuenta que los redireccionamientos no son infinitos: si presiona "Intentar de nuevo", agrega unos cuantos más /Errors/a la URL y luego se detiene después de recibir HTTP 400 Bad Request. Pero esto podría ser un mejor desbordamiento de pila que una redirección infinita.
nandhp
@nandhp, estoy de acuerdo, pero si crees que un navegador del tercer mundo (no moderno, IE, etc.), no tienen idea de esta situación.
codeSetter
2
Así es como Wget responde aquí: pastebin.com/pPRktM1m
bwDraco
1
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/...
Vortico
31

PHP

Un stackoverflow hecho solo con elementos de bucle.

$a = array(&$a);
while (1) {
    foreach ($a as &$tmp) {
        $tmp = array($tmp, &$a);
    }
}

Explicación (pase el cursor para ver el spoiler):

El programa se segfault cuando el intérprete intenta recolectar basura de la $tmpmatriz (al reasignar $tmpaquí). Solo porque la matriz es demasiado profunda (referencia propia) y luego el recolector de basura termina en una recursión.

bwoebi
fuente
16
¿El GC de PHP no puede detectar estructuras autorreferenciales? ¡¿De Verdad?! Ay. Eso es malo
Peter C
1
Sí, pero no es perfecto. Hay alguna razón por la while (1) { $a = array(&$a); }o algo similar simplemente golpea el límite de memoria ...
bwoebi
sí, creo que es la misma razón por la que PHP tampoco funciona correctamente con respecto al desarrollo orientado a objetos; (abstracción, herencia, etc.)
pythonian29033
1
@ pythonian29033 cuidado de elaborar?
vvondra
30

Java

Hice exactamente lo contrario: un programa que obviamente debería arrojar un error de desbordamiento de pila, pero no lo hace.

public class Evil {
    public static void main(String[] args) {
        recurse();
    }

    private static void recurse() {
        try {
            recurse();
        } finally {
            recurse();
        }
    }
}

Sugerencia: el programa se ejecuta en tiempo O (2 n ), yn es el tamaño de la pila (generalmente 1024).

De Java Puzzlers # 45:

Supongamos que nuestra máquina puede ejecutar 10 10 llamadas por segundo y generar 10 10 excepciones por segundo, lo cual es bastante generoso para los estándares actuales. Según estos supuestos, el programa finalizará en aproximadamente 1.7 × 10 291 años. Para poner esto en perspectiva, la vida útil de nuestro sol se estima en 10 10 años, por lo que es una apuesta segura que ninguno de nosotros estará presente para ver que este programa finalice. Aunque no es un bucle infinito, también podría serlo.

ntoskrnl
fuente
3
Recurrencia obvia ... no muy interesante.
Kami
55
@Kami ¿Lo has probado? ¿Realmente obtuviste un StackOverflowError? Parece obvio, pero no lo es.
ntoskrnl
El hecho de que se detecte una excepción no significa que nunca se haya lanzado. Este programa genera una excepción de desbordamiento de pila después del tiempo O (n)
CodesInChaos
1
@CodesInChaos Bien, entonces verifiqué esto dos veces, y la versión correcta usa en finallylugar de catch, y el tiempo de ejecución es O (2 ^ n). Respuesta actualizada
ntoskrnl
@ntorkrnl bonito uno + 1'd; por cierto, el compilador ya está en stackoverflow (el compilador se ejecuta dentro de la VM, también para tu información)
masterX244
30

C#

Primera publicación, así que por favor ve con calma

class Program
{
    static void Main()
    {
        new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Invoke(null, null);
    }
}

Esto simplemente crea un seguimiento de la pila, toma el marco superior (que será nuestra última llamada Main()), obtiene el método y lo invoca.

BenM
fuente
buena forma de autoeliminar que no es tan obvio sin explicarlo; Hecho +1
masterX244
Deberías comentar ese código con "¿qué podría salir mal?": P
Spaceman
26

Java

  • En Java 5, printStackTrace()ingresa un bucle infinito.
  • En Java 6, printStackTrace()tira StackOverflowError.
  • En Java 7 y 8, se solucionó.

Lo loco es que en Java 5 y 6, no proviene del código de usuario, sucede en el código de JDK. Nadie sospecha razonablemente que printStackTrace()pueda ser peligroso ejecutar.

public class Bad {
    public static void main(String[] args) {
        try {
            evilMethod();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void evilMethod() throws Exception {
        Exception a = new Exception();
        Exception b = new Exception(a);
        a.initCause(b);
        throw a;
    }
}
Victor Stafusa
fuente
77
sí; stackoverflows de la nada son el mejor amigo para el control de código y un serio dolor de cabeza al cazarlos
masterX244
2
Si alguien se pregunta, el código equivalente en C # provoca un bucle infinito. Pero la InnerExceptionpropiedad es de solo lectura y se establece en el constructor, por lo que es necesario reflexionar para causar esto.
Athari
17

JavaScript: mutación de función iterativa no recursiva

var f = function() {
    console.log(arguments.length);
};

while (true) {
    f = f.bind(null, 1);
    f();
}

No hay recursividad aquí en absoluto. fse repetirá repetidamente con más y más argumentos hasta que pueda desbordar la pila en una sola llamada de función. La console.logparte es opcional en caso de que desee ver cuántos argumentos se necesitan para hacerlo. También asegura que los motores JS inteligentes no optimicen esto.

Versión de código de golf en CoffeeScript, 28 caracteres:

f=->
do f=f.bind f,1 while 1
Justin Morgan
fuente
14

C # con un fracaso épico

using System.Xml.Serialization;

[XmlRoot]
public class P
{
    public P X { get { return new P(); } set { } }
    static void Main()
    {
        new XmlSerializer(typeof(P)).Serialize(System.Console.Out, new P());
    }
}

La forma en que falla es épica, me dejó alucinado por completo:

ingrese la descripción de la imagen aquí

Es solo un fotograma de una serie de imágenes extrañas aparentemente infinitas.

Esto tiene que ser lo más raro que haya existido. ¿Alguien puede explicar? Aparentemente, la cantidad cada vez mayor de espacios utilizados para la sangría hace que aparezcan esos bloques blancos. Sucede en un Win7 Enterprise x64 con .NET 4.5.

Aún no he visto el final. Si reemplaza System.Console.Outcon System.IO.Stream.Null, muere bastante rápido.

La explicación es bastante simple. Hago una clase que tiene una sola propiedad, y siempre devuelve una nueva instancia de su tipo que contiene. Entonces es una jerarquía de objetos infinitamente profunda. Ahora necesitamos algo que intente leerlo. Ahí es donde uso el XmlSerializer, que hace exactamente eso. Y aparentemente, usa la recursividad.

fejesjoco
fuente
sí; serializar ftw: P; pero más gracioso es cuando el capricho está completamente fuera de su código, como cómo snakeyaml obtiene los atributos y una clase se devuelve de una manera que se repite sin parar
masterX244
1
Bueno, el desbordamiento ocurre fuera de mi código, pero la verdadera razón por la que publiqué esto es por el inesperado efecto secundario en la consola :-)
fejesjoco
Creo que los bits blancos deben tener que ver con .Net 4.5 o cómo está configurado su entorno, porque al usar .Net 4 (incluso cuando se ejecuta a través de cmd) solo obtengo espacios, no bloques blancos. Supongo que la versión Win7 Enterprise de cmd o el emulador de consola .Net 4.5 tratan una determinada combinación de caracteres como "cambiar el fondo de color de la consola".
Pharap
No puedo reproducirlo con .NET 4.5 en Win7 x64 Professional con Aero activado
Ray
No se puede reproducir, tampoco. .NET 4.5, Windows 8.1 Pro.
bwDraco
13

golpetazo

_(){ _;};_

Si bien muchos podrían reconocer que la recursión es obvia , pero parece bonita. ¿No?

Tras la ejecución, tiene la garantía de ver:

Segmentation fault (core dumped)
devnull
fuente
55
este es más bonito y peor:_(){_|_;};_
RSFalcon7
1
@ RSFalcon7 ¡Alerta de Forkbomb! (Además, ¿no necesita un espacio después de {que sea sintácticamente correcto?)
Blacklight Shining
3
Prueba esto también:(){:|:;}:
Tarek Eldeeb
14
Parece un emoticón espeluznante y mutante.
Tim Seguine
8
Emoticones de Bash: devorador de rostros, asesino de montones.
NobleUplift
12

Haskell

(triste pero cierto hasta al menos ghc-7.6, aunque con O1o más optimizará el problema)

main = print $ sum [1 .. 100000000]
dejó de girar en sentido antihorario
fuente
¿No debería hacer una optimización de llamada de cola automáticamente (en suma)?
blabla999
2
@ blabla999: las llamadas de cola no son tan relevantes en Haskell, es principalmente la acumulación de golpes debido a la pereza encubierta que está causando tales problemas. En este caso, el problema es que sumse implementa en términos de foldl, que usa llamadas de cola, pero debido a que no evalúa estrictamente el acumulador, simplemente produce una pila de thunks tan grandes como la lista original. El problema desaparece al cambiar a foldl' (+), que evalúa estrictamente y, por lo tanto, devuelve un WHN en su cola. O, como dije, ¡si activa las optimizaciones de GHC!
dejó de girar en sentido contrario a las agujas del reloj
aah: interesante, así que si nadie esperaría el golpe (es decir, dejando fuera la impresión), ¿el recolector de basura los recogería (de adelante hacia atrás)?
blabla999
1
Por cierto, nada de esto está realmente especificado por el estándar Haskell: simplemente se requiere que la evaluación no sea estricta , es decir, un cálculo no determinante no se bloqueará para siempre si el resultado no es completamente necesario. El tiempo que realmente bloquea depende de la implementación, en GHC estándar lento no se bloquea en absoluto hasta que solicite el resultado.
dejó de girar en sentido contrario a las agujas del reloj
2
Haskell es genial.
blabla999
12

Charla

Esto crea un nuevo método sobre la marcha, que
  crea un nuevo método sobre la marcha, que
    crea un nuevo método sobre la marcha, que
      ...
    ...
  ..
y luego se transfiere a él.

Una pequeña especia extra proviene de estresar la memoria de la pila Y la memoria del montón al mismo tiempo, al crear un nombre de método más largo y más largo, y un gran número como receptor, a medida que caemos por el agujero ... (pero la recursión nos golpea primero )

compilar en entero:

downTheRabbitHole
    |name deeperName nextLevel|

    nextLevel := self * 2.
    name := thisContext selector.
    deeperName := (name , '_') asSymbol.
    Class withoutUpdatingChangesDo:[
        nextLevel class 
            compile:deeperName , (thisContext method source copyFrom:name size+1).
    ].
    Transcript show:self; showCR:' - and down the rabbit hole...'.
    "/ self halt. "/ enable for debugging
    nextLevel perform:deeperName.

luego salta, evaluando "2 downTheRabbitHole"...
... después de un tiempo, terminarás en un depurador, mostrando una RecursionException.

Luego tienes que limpiar todo el desorden (tanto SmallInteger como LargeInteger ahora tienen mucho código de país de las maravillas):

{SmallInteger . LargeInteger } do:[:eachInfectedClass |
    (eachInfectedClass methodDictionary keys 
        select:[:nm| nm startsWith:'downTheRabbitHole_'])
            do:[:each| eachInfectedClass removeSelector:each]

o de lo contrario pasar algún tiempo en el navegador, eliminando el país de las maravillas de Alice

Aquí hay algunos de la cabeza del rastro:

2 - and down the rabbit hole...
4 - and down the rabbit hole...
8 - and down the rabbit hole...
16 - and down the rabbit hole...
[...]
576460752303423488 - and down the rabbit hole...
1152921504606846976 - and down the rabbit hole...
2305843009213693952 - and down the rabbit hole...
[...]
1267650600228229401496703205376 - and down the rabbit hole...
2535301200456458802993406410752 - and down the rabbit hole...
5070602400912917605986812821504 - and down the rabbit hole...
[...]
162259276829213363391578010288128 - and down the rabbit hole...
324518553658426726783156020576256 - and down the rabbit hole...
[...]
and so on...

PD: se agregó el "withoutUpdatingChangesFile:" para evitar tener que limpiar el archivo de registro de cambios persistente de Smalltalk después.

PPS: gracias por el desafío: ¡pensar en algo nuevo e innovador fue divertido!

PPPS: Me gustaría señalar que algunos dialectos / versiones de Smalltalk copian los marcos de pila desbordados en el montón, por lo que en su lugar pueden quedar sin memoria.

blabla999
fuente
2
LOL +1 para esa magia negra en su forma pura
masterX244
Si encuentro algo de tiempo, puedo "mejorar" usando un método anónimo de una clase anónima, para hacer la madriguera más oscura de la historia ...
blabla999
12

C#

Realmente grande struct, sin recursividad, C # puro, código no inseguro.

public struct Wyern
{
    double a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
}
public struct Godzilla
{
    Wyern a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
}
public struct Cyclops
{
    Godzilla a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
}
public struct Titan
{
    Cyclops a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
}
class Program
{
    static void Main(string[] args)
    {
        // An unhandled exception of type 'System.StackOverflowException' occurred in ConsoleApplication1.exe
        var A=new Titan();
        // 26×26×26×26×8 = 3655808 bytes            
        Console.WriteLine("Size={0}", Marshal.SizeOf(A));
    }
}

como pateador, bloquea las ventanas de depuración indicando que {Cannot evaluate expression because the current thread is in a stack overflow state.}


Y la versión genérica (gracias por la sugerencia NPSF3000)

public struct Wyern<T>
    where T: struct
{
    T a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;        
}


class Program
{
    static void Main(string[] args)
    {
        // An unhandled exception of type 'System.StackOverflowException' occurred in ConsoleApplication1.exe
        var A=new Wyern<Wyern<Wyern<Wyern<int>>>>();
    }
}
ja72
fuente
Necesita más
ideas de
Se vería como una recursión, pero es posible con argumentos de tipo anidados.
ja72
1
No vi tu respuesta de C # struct antes de publicar la mía. Todavía tengo un enfoque un poco diferente, así que tal vez dejamos que coexistan.
Thomas Weller
11

C#

Implementación defectuosa del ==operador anulado :

public class MyClass
{
    public int A { get; set; }

    public static bool operator ==(MyClass obj1, MyClass obj2)
    {
        if (obj1 == null)
        {
            return obj2 == null;
        }
        else
        {
            return obj1.Equals(obj2);
        }
    }

    public static bool operator !=(MyClass obj1, MyClass obj2)
    {
        return !(obj1 == obj2);
    }

    public override bool Equals(object obj)
    {
        MyClass other = obj as MyClass;
        if (other == null)
        {
            return false;
        }
        else
        {
            return A == other.A;
        }
    }
}

Se podría decir que es obvio que se operator==llama a sí mismo utilizando el ==operador, pero generalmente no piensas de esa manera ==, por lo que es fácil caer en esa trampa.

Sebastian Negraszus
fuente
11

Iniciando respuesta usando SnakeYAML

class A
{

    public static void main(String[] a)
    {
         new org.yaml.snakeyaml.Yaml().dump(new java.awt.Point());
    }
}

Editar: sin golf

Depende del lector descubrir cómo funciona: P (consejo: stackoverflow.com)

Por cierto: SnakeYAML crea dinámicamente la recursividad (notará si sabe cómo detecta los campos que serializa y luego mira en Pointel código fuente)

Editar: diciendo cómo funciona ese:

SnakeYAML busca un par de getXXXy setXXXmthod con el mismo nombre XXXy el tipo de retorno del getter es el mismo que el parámetro de setter; y sorprendentemente la Pointclase tiene un Point getLocation()y void setLocation(Point P)que regresa a sí mismo; SnakeYAML no lo nota y recurre a ese capricho y StackOverflows. Descubrí eso cuando trabajaste con ellos dentro de HashMapy preguntando en stackoverflow.com sobre él.

masterX244
fuente
10

C#

getter de propiedad implementado incorrectamente

class C
{
   public int P { get { return P; } }
}

static void Main()
{
   int p = new C().P;
}
Alberto
fuente
14
EN MI HUMILDE OPINIÓN. Este es un ejemplo clásico de una recurrencia obvia ... (y por lo tanto no es válido)
Ole Albers
2
Bueno, solo es obvio una vez que lo has hecho una vez y descubriste que los captadores de C # no funcionan de la manera que pensaste que lo hicieron. Después de todo, este código es una declaración de variable miembro, entonces, ¿por qué no debería crear una variable miembro real?
meustrus
2
Esto no es más que una forma complicada de hacerstatic void Main() { Main(); }
Jodrell
55
@Jodrell No escribirías recursivamente Main()accidentalmente. Pero es bastante simple escribir una propiedad recursiva accidentalmente y luego confundirse con el desbordamiento de la pila.
svick
1
Esto sería útil para alguien que recoja C #.
2rs2ts