导致堆栈溢出的最短代码是什么?[关闭]


160

为了纪念Stack Overflow的公开发布,导致堆栈溢出的最短代码是什么?任何语言的欢迎。

ETA:在这个问题上要清楚一点,因为我偶尔是Scheme用户:尾调用“递归”实际上是迭代,因此任何可以由像样的编译器相对简单地转换为迭代解决方案的解决方案都不会被算在内。:-P

ETA2:我现在选择了“最佳答案”。请参阅此帖子以了解基本原理。感谢所有贡献者!:-)

Answers:


212

所有这些答案,没有Befunge吗?我敢打赌,这是所有这些中最短的解决方案:

1

不开玩笑。自己尝试:http : //www.quirkster.com/iano/js/befunge.html

编辑:我想我需要解释这一点。1操作数将1压入Befunge的内部堆栈,由于缺少其他任何条件,它在语言规则下处于循环状态。

使用提供的解释器,您最终-我的意思是最终-达到了一个点,在该点上,代表Befunge堆栈的Javascript数组变得太大,以至于浏览器无法重新分配。如果您有一个简单的Befunge解释器,且堆栈较小且有界(以下大多数语言都是这种情况),则此程序将更快地引起更明显的溢出。


8
嗯……但这真的是堆栈溢出还是无限循环?我的JS解释并没有溢出,它只是去度假,可以这么说。
Konrad Rudolph

3
这不是无限循环,因为1指令将1压入堆栈。最终,您的Befunge解释器将耗尽堆栈空间,但需要一段时间。:)
Patrick Patrick

18
您..崩溃了我的浏览器,并且..使我的CPU风扇超速了。
2009年

2
惊人!我的计算机或浏览器(Opera)没有崩溃,但是两个处理器都以100%运行,风扇速度为
3。– Secko

28
下面是溢出快Befunge程序: " 它加载它环绕每两次,32号的79个副本,而不是数字1的2份
KirarinSnow


174

您也可以在C#.net中尝试

throw new StackOverflowException();

29
我里面的学徒说这不会导致任何堆栈溢出,只会引发异常。这就像说要受到鲨鱼袭击的最快方法是站在海中并大喊“鲨鱼袭击!”。尽管如此,我还是会投票。:)
伯纳德

好吧-有区别吗?你能抓住它并继续吗?还是完全像C#中的stackoverflow?在那种情况下,它某种程度上是一个stackoverflow,因为它与一个是无法区分的。。。但是-由于上述所有原因而投票
Mo.

18
如果堆栈在树林中溢出而没有人围住,会引发异常吗?

我不会说“最短的”,因为这不是您可以像这样编译一个单线。虽然我猜它确实会迅速引发堆栈溢出。
多米尼克K


119

我目前最好的(在x86汇编中)是:

push eax
jmp short $-1

结果是3个字节的目标代码(50 EB FD)。对于16位代码,这也是可能的:

call $

这也将导致3个字节(E8 FD FF)。


6
在“编译”(或组装)之后计算字节数不是代码高尔夫。
路易·布兰迪

37
这个问题说:“ [...]导致堆栈溢出的最短代码是什么?” 它没有指定源代码,解释代码,机器代码,目标代码或托管代码...
Anders Sandvig

作为记录,Shin的高尔夫服务器允许您发送要判断的目标代码,尽管它也会计算所有ELF标头。嗯....
克里斯·杰斯特·杨

有关此示例,请参见例如golf.shinh.org/p.rb?FizzBu​​zz#x86。(不过,老实说,我不知道人们如何制作99字节的ELF二进制文件。):-P
克里斯·杰斯特·杨

7
@lbrandy:有足够的人可以直接编写目标代码。对于x86,我无法做到,但是对于某些微处理器,我可以。我会计算这样的代码。
乔伊,2010年

113

PIC18

TK给出PIC18答案产生以下指令(二进制):

overflow
   PUSH
   0000 0000 0000 0101
   CALL overflow
   1110 1100 0000 0000
   0000 0000 0000 0000

但是,仅CALL会执行堆栈溢出:

CALL $
1110 1100 0000 0000
0000 0000 0000 0000

较小,更快的PIC18

但是RCALL(相对调用)仍然较小(不是全局内存,因此不需要额外的2个字节):

RCALL $
1101 1000 0000 0000

因此,PIC18上最小的是一条指令,即16位(两个字节)。每个循环将花费2个指令周期。每个指令周期有4个时钟周期,您就有8个时钟周期。PIC18具有31级堆栈,因此在第32次循环之后,它将在256个时钟周期内使堆栈溢出。在64MHz下,您将在4微秒和2个字节内使堆栈溢出

PIC16F5x(甚至更小,更快)

但是,PIC16F5x系列使用12位指令:

CALL $
1001 0000 0000

同样,每个循环两个指令周期,每个指令4个时钟,因此每个循环8个时钟周期。

但是,PIC16F5x具有两级堆栈,因此在第三个循环中,它将以24条指令溢出。在20MHz时,它将在1.2微秒和1.5个字节内溢出

英特尔4004

英特尔4004有一个8位CALL指令:

CALL $
0101 0000

对于与ascii“ P”相对应的好奇。3级堆栈需要24个时钟周期,总共需要32.4微秒和1个字节。(除非您对4004进行超频-来吧,否则您就知道要这么做。)

它与befunge答案一样小,但是比当前解释器中运行的befunge代码快得多。


77

C#:

public int Foo { get { return Foo; } }

57

嘶哑溢出!

//              v___v
let rec f o = f(o);(o)
//             ['---']
//             -"---"-

55

每个任务都需要正确的工具。符合SO Overflow语言,经过优化可产生堆栈溢出:

so

7
如果您要使用一种特殊的语言来使用最少的代码来生成溢出,那么显然您会希望(1)空输入会产生堆栈溢出代码(可能是一个小的二进制文件,用于运行从汇编代码条目生成的本机代码)或(2 )所有输入程序都产生所说的二进制。
Jared Updike

嗯,不是图灵完成的。我不知道您是否还可以将其称为一种语言……
亚当·戴维斯

42

TeX:

\def~{~.}~

结果是:

!超出TeX容量,很抱歉[输入堆栈大小= 5000]。
〜->〜
    。
〜->〜
    。
〜->〜
    。
〜->〜
    。
〜->〜
    。
〜->〜
    。
...
<*> \ def〜{〜。}〜

胶乳:

\end\end

结果是:

!超出TeX容量,很抱歉[输入堆栈大小= 5000]。
\ end#1-> \ csname end#1
                      \ endcsname \ @checkend {#1} \在\ endgroup \ if @ e之后展开...
<*> \ end \ end

由于~处于活动状态,因此可以代替使用\a。我偶然发现了LaTeX代码。:)
Josh Lee

35

Z-80汇编器-在内存位置0x0000:

rst 00

一个字节-0xC7-将当前PC推入堆栈并跳转到地址0x0000的无穷循环。


2
我记得一个空白的eprom将是所有0xffs,它们是rst 7(= call 0x0038)指令。这对于使用示波器调试硬件很有用。当堆栈反复溢出时,地址总线将在64K空间中循环,并散布着0x0038的0xff读值。
比尔·福斯特


29

另一个PHP示例:

<?
require(__FILE__);

4
您甚至可以跳过括号来缩短(但请在空格处代替第一个)。
Alex

26

BASIC中的以下内容如何:

10 GOSUB 10

(恐怕我没有BASIC解释器,这是一个猜测)。


3
由于BASIC是无堆栈语言,因此并不是真正的堆栈溢出。甚至VB(确实具有堆栈)也不会在此溢出,因为它只是在跳而不是在创建堆栈框架。
Daniel Spiewak

21
那是一个GOSUB,而不是一个GOTO。由于它RETURN是从哪里调用的,因此肯定使用了堆栈吗?
汤姆(Tom)

3
是的,我同意。在80年代,我在BASIC中有很多堆栈溢出。
昵刻

6
我只是为了娱乐而在yabasic中运行了它,它几乎毁了我的计算机。谢天谢地,malloc最终失败了,但是我明天却分页。
亚当·罗森菲尔德

2
抱歉,亚当...让我想起了我在uni的一段时间,当时有人不小心写了一个递归分叉的程序:关闭了整个Silicon Graphics服务器。
stusmith

26

我喜欢Cody的答案堆,所以这是我在C ++中的类似贡献:

template <int i>
class Overflow {
    typedef typename Overflow<i + 1>::type type;
};

typedef Overflow<0>::type Kaboom;

无论如何,这都不是代码高尔夫球场,但仍然有任何东西会导致元堆栈溢出!:-P


21

这是我的C贡献,重18个字符:

void o(){o();o();}

这是一个很多难以尾调用优化!:-P


4
不为我编译:“对“ main”的未定义引用”:P
Andrew Johnson

1
我不明白:为什么要调用o()2x?
迪纳2009年

3
@Dinah:我比赛的制约因素之一是,尾部呼叫优化不算作递归;这只是一个迭代循环。如果您只编写了一次o(),则可以(通过称职的编译器)将其尾部调用优化为以下形式:“ o:jmp o”。使用o的2次调用,编译器必须使用类似以下内容:“ o:call o; jmp o”。导致堆栈溢出的是递归的“调用”指令。
克里斯·杰斯特·杨

您是对的-我没有注意那部分。谢谢你的澄清。
黛娜


17

Java脚本

要修剪更多的字符,并让自己离开更多的软件商店,让我们开始:

eval(i='eval(i)');

15

Groovy:

main()

$ groovy stack.groovy:

Caught: java.lang.StackOverflowError
    at stack.main(stack.groovy)
    at stack.run(stack.groovy:1)
 ...

投票,因为它很有趣。但是,在Groovy编译器中暴露出一个相当烦人的弱点(此类尾调用可以在编译时内联)。
Daniel Spiewak

您确定这是个尾声吗?程序末尾掉落不会调用解释器外壳?
亚伦,


14
Person JeffAtwood;
Person JoelSpolsky;
JeffAtwood.TalkTo(JoelSpolsky);

希望没有尾递归!


1
呵呵,好笑。与对话相关,“回音室效应”的想法也很有趣。不太会引起堆栈溢出,但是仍然如此。
克里斯·杰斯特·杨

8
这不是空指针异常吗?对不起,我知道这是个玩笑。
jamesh

12

C-它不是最短的,但是没有递归。它也不是可移植的:它在Solaris上崩溃,但是某些alloca()实现可能会在此处返回错误(或调用malloc())。调用printf()是必要的。

#include <stdio.h>
#include <alloca.h>
#include <sys/resource.h>
int main(int argc, char *argv[]) {
    struct rlimit rl = {0};
    getrlimit(RLIMIT_STACK, &rl);
    (void) alloca(rl.rlim_cur);
    printf("Goodbye, world\n");
    return 0;
}

您也可以执行“ ulimit -s16”来设置堆栈很小。任何小于约16的值,程序甚至都无法运行(显然args不足!)。
Andrew Johnson

11

Perl 12个字符:

$_=sub{&$_};&$_

用10个字符组成bash(函数中的空格很重要):

i(){ i;};i


11

Python

so=lambda:so();so()

或者:

def so():so()
so()

如果Python优化了尾调用...:

o=lambda:map(o,o());o()

幸运的是,Python不会进行尾部调用优化。否则,它会像其他两个答案一样被取消资格。:-P
克里斯·杰斯特·杨

10

我在这篇文章之后选择“最佳答案”。但是首先,我想承认一些非常原始的贡献:

  1. 阿库的。每个人都探索一种导致堆栈溢出的新方法。f(x)⇒f(f(x))的想法是我将在下面的下一篇文章中探讨的想法。:-)
  2. Cody的代码使Nemerle 编译器出现了堆栈溢出。
  3. 而且(有点勉强),GateKiller的问题是引发堆栈溢出异常。:-P

尽管我很喜欢上述内容,但是挑战在于打高尔夫球,为了公平起见,对于受访者来说,我必须为最短的代码(即Befunge参赛作品)授予“最佳答案”。我不相信任何人都可以击败它(尽管Konrad确实尝试过),所以恭喜Patrick!

看到大量的递归堆栈溢出解决方案,令我感到惊讶的是,截至目前,没有人提出Y组合器(有关入门知识,请参见Dick Gabriel的文章The Why of Y)。我有一个使用Y组合器的递归解决方案,以及aku的f(f(x))方法。:-)

((Y (lambda (f) (lambda (x) (f (f x))))) #f)

8

这是Scheme中另一个有趣的内容:

((λ(x)(xx))(λ(x)(xx))))

非常好,而且对称性也很好。同样,使用(lambda(x)(xx))公式:((Y(lambda(x)(xx)))#f)也很有趣!
克里斯·杰斯特·杨

哦,很漂亮。它也可以在Ruby中使用,尽管不像Scheme中那样漂亮:lambda {| x | x.call x} .call lambda {| x | x.call x}
韦恩·康拉德

7

爪哇

Java解决方案的略短版本。

class X{public static void main(String[]a){main(a);}}

5
或(相同字符数):public static void main(String ... a){main();}
迈克尔·迈尔斯

或者对于TDD家伙(字符数相同):public class ${@org.junit.Test public void $(){$();}}
挑战者

仍然不是最短的(请参阅我的答案)
Draemon 2010年


5

3个字节:

label:
  pusha
  jmp label

更新资料

根据(old?)Intel(?)文档,这也是3个字节:

label:
  call label


在32位模式下为3字节。不错的答案,考虑到它将比我的答案快得多!
克里斯·杰斯特·杨

根据penguin.cz/~literakl/intel/j.html#JMP,jmp为3字节,相对目标地址为8、16或32位。pusha也是1个字节,总共4个字节
Anders Sandvig

jmp有三种类型,即short,near和far。简短的jmp(使用0xEB操作码)为两个字节。目标位置必须与下一条指令之间在-128到127个字节之间。:-)
克里斯·杰斯特·杨

也许你说的对。我懒得挖出我的汇编程序并验证...;)
Anders Sandvig
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.