Como programador, você certamente conhece o erro de um estouro de pilha devido a uma recursão óbvia. Mas certamente existem muitas maneiras estranhas e incomuns de obter seu idioma favorito para cuspir esse erro.
Objetivos.
- Deve causar um estouro de pilha claramente visível na saída de erro.
- Não é permitido usar uma recursão óbvia.
Exemplos de programas inválidos:
// Invalid, direct obvious recursion.
methodA(){ methodA(); }
// Invalid, indirect, but obvious recursion.
methodA(){ methodB(); }
methodB(){ methodA(); }
As formas mais criativas são as melhores, pois este é um concurso de popularidade . Ou seja, evite respostas óbvias chatas como esta:
throw new StackOverflowError(); // Valid, but very boring and downvote-deserving.
Embora eu tenha aceitado uma resposta agora, adicionar mais respostas ainda está bem :)
popularity-contest
stack
masterX244
fonte
fonte
Respostas:
Pitão
Isso fará com que o intérprete falhe imediatamente:
Em vez de usar a recursão, apenas encolhe a pilha e transborda imediatamente.
fonte
Pitão
fonte
C / Linux 32bit
Funciona substituindo o endereço de retorno. Portanto,
g
retorna ao pontomain
antes de chamarf
. Funcionará para qualquer plataforma em que os endereços de retorno estejam na pilha, mas pode exigir ajustes.Obviamente, escrever fora de uma matriz é um comportamento indefinido e você não tem garantia de que ela causará um estouro de pilha em vez de, por exemplo, pintar seu bigode de azul. Detalhes de sinalizadores de plataforma, compilador e compilação podem fazer uma grande diferença.
fonte
JavaScript / DOM
Se você quiser matar o seu navegador, tente isso no console.
fonte
with (document.body) { addEventListener('DOMSubtreeModified', function() { appendChild(firstChild); }, false); title = 'Kill me!'; } 15:43:43.642 TypeError: can't convert undefined to object
Java
Vi algo assim em algum lugar por aqui:
Edit: Encontrado onde o vi: resposta de Joe K para o programa mais curto que lança o erro StackOverflow
Isso pode confundir alguns iniciantes em Java. Ele simplesmente oculta a chamada recursiva.
val + this
torna-seval + this.toString()
porqueval
é uma String.Veja aqui: http://ideone.com/Z0sXiD
fonte
new StringBuilder().append(val).append("").append(this).toString()
, e o último anexo chama String.valueOf (...), que por sua vez chama toString. Isso faz com que seu rastreamento de pilha seja um pouco variado (três métodos nele)."" + this.toString()
.+ "" +
pode ajudar as pessoas, pois parece inútil à primeira vista.String val;
ereturn val + this;
pode ser marginalmente sneakier""
construção -String é com o+ ""
C
Muito fácil:
fonte
ulimit -s unlimited
na concha resolve este em Linux)~0u
é um número muito grande em C.Estouro de pilha não recursivo em C
Incompatibilidade de convenção de chamada.
Compile com
gcc -O0
.__cdecl
As funções esperam que o chamador limpe a pilha e__stdcall
espera que o receptor faça isso; portanto, chamando pelo ponteiro da função typecast, a limpeza nunca é feita -main
coloca o parâmetro na pilha para cada chamada, mas nada aparece e, finalmente, o pilha preenche.fonte
Javascript
fonte
+this
faz?+{toString:"".toLocaleString}
:-)Fiquei frustrado pelo fato de o java 7 e o java 8 serem imunes ao meu código maligno na minha resposta anterior . Então eu decidi que era necessário um patch para isso.
Sucesso! Eu fiz
printStackTrace()
jogar umStackOverflowError
.printStackTrace()
é comumente usado para depuração e registro em log e ninguém suspeita razoavelmente que isso possa ser perigoso. Não é difícil ver que esse código pode ser abusado para criar alguns problemas sérios de segurança:Algumas pessoas podem pensar que esta é uma recursão óbvia. Não é. O
EvilException
construtor não chama ogetCause()
método, para que a exceção possa realmente ser lançada com segurança, afinal. Chamar ogetCause()
método também não resultará em umStackOverflowError
. A recursão está dentro doprintStackTrace()
comportamento normalmente insuspeitado do JDK e em qualquer biblioteca de terceiros para depuração e criação de log usada para inspecionar a exceção. Além disso, é provável que o local onde a exceção é lançada esteja muito longe do local em que é manipulado.Enfim, aqui está um código que lança um
StackOverflowError
e não contém nenhuma chamada de método recursivo, afinal. O queStackOverflowError
acontece fora domain
método, nos JDK'sUncaughtExceptionHandler
:fonte
getCause()
método não resulta emStackOverflowError
. Ele se baseia no fato de que há um código do JDK que está chamando ogetCause()
método recursivamente .getCause
para apenas,return this;
mas aparentemente Java é inteligente demais para isso. Ele percebe que é um "CIRCULAR REFERENCE
".StackOverflowError
porque o pacote OpenBSD 5.5 do jdk-1.7.0.21p2v0 tem um erro. Não jogaStackOverflowError
. Ele atingeSIGSEGV
e despeja o núcleo.Montagem NASM do Linux x86
Spoiler:
fonte
ret
C ++ em tempo de compilação
Não há recursão nesse arquivo de origem, nenhuma das classes tem ela própria como classe base, nem indiretamente. (Em C ++, em uma classe de modelo como essa
S<1>
eS<2>
são classes completamente distintas.) A falha de segmentação ocorre devido ao estouro de pilha após recursão no compilador.fonte
template <typename T> auto foo(T t) -> decltype(foo(t)); decltype(foo(0)) x;
é um pouco mais curto.Bash (Alerta de Perigo)
Estritamente falando, isso não empilhará diretamente o estouro, mas gera o que pode ser rotulado como " uma situação persistente de geração de excesso de pilha ": quando você executa isso até o disco ficar cheio e deseja remover a bagunça com "rm -rf x ", esse é atingido.
Porém, isso não acontece em todos os sistemas. Alguns são mais robustos que outros.
Grande perigo AVISO:
alguns sistemas lidam com isso muito mal e você pode ter muita dificuldade em limpar (porque "rm -rf" pode ter um problema de recusa). Pode ser necessário escrever um script semelhante para a limpeza.
É melhor tentar isso em uma VM temporária, se não tiver certeza.
PS: o mesmo se aplica, é claro, se programado ou feito em um script em lote.
PPS: pode ser interessante receber um comentário de você, como seu sistema específico se comporta ...
fonte
while cd x; do :; done; cd ..; while rmdir x; cd ..; done;
deveria cuidar disso.Java
Um bom dos Java Puzzlers . O que é impresso?
Na verdade, ele falha com um StackOverflowError.
A exceção no construtor é apenas um arenque vermelho. Isto é o que o livro tem a dizer sobre isso:
fonte
Látex
A pilha de entrada transborda porque
\end
se expande repetidamente em um loop infinito, conforme explicado aqui .O TeX falha com um
TeX capacity exceeded, sorry [input stack size=5000]
ou similar.fonte
BF
Eventualmente, ela excederá a pilha, depende apenas de quanto tempo o intérprete faz a pilha ...
fonte
C #, em tempo de compilação
Existem várias maneiras de fazer com que o compilador Microsoft C # expanda sua pilha; sempre que você vir um erro "a expressão é muito complexa para compilar" no compilador C #, quase certamente porque a pilha explodiu.
O analisador é descendente recursivo, portanto, qualquer estrutura de linguagem suficientemente profundamente aninhada explodirá a pilha:
O analisador de expressão é bastante inteligente em eliminar recursões no lado comumente recorrente. Usualmente:
que constrói uma árvore de análise imensamente profunda, não explodirá a pilha. Mas se você forçar a recursão a acontecer do outro lado:
então a pilha pode ser explodida.
Eles têm a propriedade deselegante de que o programa é muito grande. Também é possível fazer o analisador semântico entrar em recursões ilimitadas com um programa pequeno, porque não é inteligente o suficiente para remover certos ciclos ímpares no sistema de tipos. (Roslyn pode melhorar isso.)
Descrevo por que essa análise entra em uma recursão infinita aqui:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx
e para muitos outros exemplos interessantes, você deve ler este artigo:
http://research.microsoft.com/en-us/um/people/akenn/generics/FOOL2007.pdf
fonte
fatal error CS1647: An expression is too long or complex to compile near (code)
. A documentação para esta mensagem de erro está aqui e é exatamente como você diz: "Houve um estouro de pilha no compilador que processava seu código".Na Internet (usada por bilhões de pessoas / dia)
Por exemplo, no site de suporte da Dell (sem ofensa, desculpe Dell):
Se você remover o TAG de suporte do URL, ele será redirecionado infinitamente . No URL a seguir, ###### é qualquer TAG de suporte.
http://www.dell.com/support/drivers/uk/en/ukdhs1/ServiceTag/######?s=BSD&~ck=mn
Eu acredito que é equivalente a um estouro de pilha.
fonte
/Errors/
ao URL e pára depois de receber HTTP 400 Bad Request. Mas isso pode gerar um estouro de pilha melhor do que um redirecionamento infinito.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
Um stackoverflow feito apenas com elementos de loop.
Explicação (passe o mouse para ver o spoiler):
fonte
while (1) { $a = array(&$a); }
ou algo similar apenas atinge o limite de memória ...Java
Fiz exatamente o oposto - um programa que obviamente deveria gerar um erro de estouro de pilha, mas não o faz.
Dica: o programa é executado em O (2 n tempo), e n é o tamanho da pilha (geralmente 1024).
De Java Puzzlers # 45:
fonte
finally
e nãocatch
, e o tempo de execução é O (2 ^ n). Resposta atualizada.C #
Primeiro post, por favor, vá com calma comigo.
Isso simplesmente cria um rastreamento de pilha, pega o quadro superior (que será nossa última chamada
Main()
), obtém o método e o invoca.fonte
Java
printStackTrace()
insere um loop infinito.printStackTrace()
lançaStackOverflowError
.O mais louco é que, no Java 5 e 6, ele não vem do código do usuário, acontece no código do JDK. Ninguém suspeita razoável que
printStackTrace()
possa ser perigoso de executar.fonte
InnerException
propriedade é somente leitura e é definida no construtor; portanto, é necessária reflexão para causar isso.JavaScript: mutação de função iterativa não recursiva
Não há recursão aqui.
f
será repetidamente repetido com mais e mais argumentos até que possa estourar a pilha em uma única chamada de função. Aconsole.log
peça é opcional caso você queira ver quantos argumentos são necessários para isso. Ele também garante que mecanismos JS inteligentes não otimizarão isso.Versão Code-golf no CoffeeScript, 28 caracteres:
fonte
C # com uma falha épica
O jeito que ele falha é épico, me surpreendeu completamente:
É apenas um quadro de uma série aparentemente infinita de imagens estranhas.
Isso deve ser a coisa mais estranha de todas. Alguém pode explicar? Aparentemente, a quantidade cada vez maior de espaços usados para indentação faz com que esses blocos brancos apareçam. Isso acontece em um Win7 Enterprise x64 com o .NET 4.5.
Eu ainda não vi o fim disso ainda. Se você substituir
System.Console.Out
comSystem.IO.Stream.Null
, morre muito rápido.A explicação é bem simples. Eu faço uma classe que possui uma única propriedade e ela sempre retorna uma nova instância do seu tipo de contenção. Portanto, é uma hierarquia de objetos infinitamente profunda. Agora precisamos de algo que tente ler isso. É aí que eu uso o
XmlSerializer
, o que faz exatamente isso. E, aparentemente, ele usa recursão.fonte
bater
Enquanto muitos podem reconhecer que a recursão é óbvia , mas parece bonita. Não?
Após a execução, você tem a garantia de ver:
fonte
_(){_|_;};_
{
ser sintaticamente correto?):(){:|:;}:
Haskell
(triste, mas verdadeiro até pelo menos
ghc-7.6
, embora comO1
ou mais otimize o problema)fonte
sum
é implementado em termos defoldl
, que usa chamadas de cauda, mas porque não avalia o acumulador estritamente apenas produz uma pilha de thunks do tamanho da lista original. O problema desaparece ao mudar parafoldl' (+)
, que avalia estritamente e, portanto, retorna um WHN em sua chamada final. Ou, como eu disse, se você ativar as otimizações do GHC!Conversa fiada
Isso cria um novo método em tempo real, que
cria um novo método em tempo real, que
cria um novo método em tempo real, que
...
...
..
e depois transfere para ele.
Um pouco mais de tempero vem do estresse da memória da pilha E da memória da pilha ao mesmo tempo, criando um nome de método cada vez mais longo e um grande número como receptor, quando caímos no buraco ... (mas a recursão nos atinge primeiro )
compilar em número inteiro:
depois pule, avaliando
"2 downTheRabbitHole"
...... depois de um tempo, você terminará em um depurador, mostrando uma RecursionException.
Então você precisa limpar toda a bagunça (o SmallInteger e o LargeInteger agora têm muito código do país das maravilhas):
ou então, passe algum tempo no navegador, removendo o país das maravilhas de alice.
Aqui estão alguns dos principais traços:
PS: o "withoutUpdatingChangesFile:" foi adicionado para evitar a necessidade de limpar o arquivo de log de alterações persistente do Smalltalk posteriormente.
PPS: obrigado pelo desafio: pensar em algo novo e inovador foi divertido!
PPPS: Eu gosto de observar que algumas versões / dialetos do Smalltalk copiam quadros de pilha transbordantes para o heap - portanto, eles podem ter uma situação de falta de memória.
fonte
C #
Realmente grande
struct
, sem recursão, C # puro, código não seguro.como um kicker ele trava as janelas de depuração afirmando que
{Cannot evaluate expression because the current thread is in a stack overflow state.}
E a versão genérica (obrigado pela sugestão NPSF3000)
fonte
C #
Implementação defeituosa do
==
operador substituído :Pode-se dizer que é óbvio que se
operator==
chama usando o==
operador, mas você geralmente não pensa assim==
, por isso é fácil cair nessa armadilha.fonte
Iniciando a resposta usando o SnakeYAML
Editar: ungolfed it
Cabe ao leitor descobrir como isso funciona: P (dica: stackoverflow.com)
A propósito: a recursão é feita dinamicamente pelo SnakeYAML (você notará se souber como ele detecta os campos que serializa e depois olhará
Point
código-fonte)Edit: dizendo como isso funciona:
O SnakeYAML procura um par de
getXXX
esetXXX
mthod com o mesmo nomeXXX
e o tipo de retorno do getter é o mesmo que o parâmetro do setter; e surpreendentemente aPoint
classe tem umPoint getLocation()
evoid setLocation(Point P)
que se retorna; O SnakeYAML não percebe e se repete nessa peculiaridade e StackOverflows. Descobriu aquele ao trabalhar com eles dentro de umHashMap
e perguntando sobre stackoverflow.com.fonte
C #
getter de propriedade implementado incorretamente
fonte
static void Main() { Main(); }
Main()
acidentalmente. Mas é bastante simples escrever uma propriedade recursiva acidentalmente e depois ficar confuso com o estouro da pilha.