Какой самый короткий код вызывает переполнение стека?

Чтобы отметить публичный запуск переполнения стека, какой самый короткий код вызывает переполнение стека? Любой язык приветствуется.

ETA: Просто чтобы прояснить этот вопрос, поскольку я случайный пользователь Scheme: хвостовой вызов "recursion" - это действительно итерация, и любое решение, которое может быть преобразовано в итеративное решение относительно тривиально приличным компилятором, не будет быть посчитанным.:-П

ETA2: я сейчас выбрал "лучший ответ"; см. этот пост для обоснования. Спасибо всем, кто внес свой вклад!:-)

131 ответ

Решение

Все эти ответы и не Befunge? Держу пари, что это самое короткое решение из всех:

1

Без шуток. Попробуйте сами: http://www.quirkster.com/iano/js/befunge.html

РЕДАКТИРОВАТЬ: Я думаю, мне нужно объяснить это. Операнд 1 помещает 1 во внутренний стек Befunge, а отсутствие чего-либо еще помещает его в цикл в соответствии с правилами языка.

Используя предоставленный интерпретатор, вы в конечном итоге - и я имею в виду - в конечном итоге - попадете в точку, в которой массив Javascript, представляющий стек Befunge, становится слишком большим для перераспределения браузера. Если бы у вас был простой интерпретатор Befunge с меньшим и ограниченным стеком - как в случае с большинством языков ниже - эта программа вызовет более заметное переполнение быстрее.

Прочитайте эту строку и сделайте то, что она говорит дважды.

Вы также можете попробовать это в C#.net

throw new StackruException();

Nemerle:

Это приводит к аварийному завершению работы компилятора с StackruException:

def o(){[o()]}

Мой текущий лучший (в сборке x86):

push eax
jmp short $-1

в результате получается 3 байта объектного кода (50 EB FD). Для 16-битного кода это также возможно:

call $

что также дает 3 байта (E8 FD FF).

PIC18

Ответ PIC18, данный TK, приводит к следующим инструкциям (двоичный код):

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 тактов. На 64 МГц вы переполните стек за 4 микросекунды и 2 байта.

PIC16F5x (еще меньше и быстрее)

Тем не менее, серия PIC16F5x использует 12-битные инструкции:

CALL $
1001 0000 0000

Опять же, два цикла команд на цикл, 4 такта на инструкцию, поэтому 8 тактов на цикл.

Однако PIC16F5x имеет двухуровневый стек, поэтому в третьем цикле он будет переполнен в 24 инструкциях. При 20 МГц он будет переполнен за 1,2 микросекунды и 1,5 байта.

Intel 4004

Intel 4004 имеет 8-битную инструкцию подпрограммы вызова:

CALL $
0101 0000

Для любопытных, которые соответствуют ascii 'P'. С 3-уровневым стеком, который занимает 24 такта в общей сложности 32,4 микросекунды и один байт. (Если вы не разгоните свой 4004 - давай, ты знаешь, что хочешь.)

Это так же мало, как ответ befunge, но намного, намного быстрее, чем код befunge, работающий в современных интерпретаторах.

C#:

public int Foo { get { return Foo; } }

Гудок переполнен!

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

Каждое задание нуждается в правильном инструменте. Познакомьтесь с языком SO Overflow, оптимизированным для переполнения стека:

so

TeX:

\def~{~.}~

Результаты в:

! Превышена емкость TeX, извините [размер входного стека =5000].
~->~,
~ -> ~,
~ -> ~,
~ -> ~,
~ -> ~,
~ -> ~,...<*> \ def ~ {~.} ~

Латекс:

\end\end

Результаты в:

! Превышена емкость TeX, извините [размер входного стека = 5000].
\ end # 1 -> \ csname end # 1
                      \ endcsname \ @checkend {# 1} \ expandafter \ endgroup \ if @ e...<*> \ end \ end

Ассемблер Z-80 - в ячейке памяти 0x0000:

rst 00

один байт - 0xC7 - бесконечный цикл загрузки текущего ПК в стек и перехода к адресу 0x0000.

Другой пример PHP:

<?
require(__FILE__);

По-английски:

recursion = n. See recursion.

Как насчет следующего в бейсике:

10 GOSUB 10

(Боюсь, у меня нет переводчика бейсика, так что это предположение).

Мне понравилась куча ответов Коди, поэтому вот мой аналогичный вклад в C++:

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

typedef Overflow<0>::type Kaboom;

Ни в коем случае не кодовая игра в гольф, но все же что-нибудь для переполнения мета-стека!:-П

Вот мой вклад C, весом 18 символов:

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

Это намного сложнее оптимизировать!:-П

Используя пакетный файл окна с именем "s.bat":

call s

Javascript

Чтобы урезать еще несколько персонажей и выкинуть себя из других программных магазинов, давайте перейдем к:

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

Пожалуйста, скажите мне, что означает аббревиатура " GNU".

Groovy:

main()

$ groovy stack.groovy:

Caught: java.lang.StackruError
    at stack.main(stack.groovy)
    at stack.run(stack.groovy:1)
 ...
Person JeffAtwood;
Person JoelSpolsky;
JeffAtwood.TalkTo(JoelSpolsky);

Здесь надеемся на отсутствие хвостовой рекурсии!

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;
}

Python:

so=lambda:so();so()

В качестве альтернативы:

def so():so()
so()

И если Python оптимизировал хвостовые вызовы...:

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

Попробуйте положить более 4 пирожков на один бургер. переполнение стека.

Perl в 12 символов:

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

bash в 10 символов (пробел в функции важен):

i(){ i;};i

Я выбираю "лучший ответ" после этого поста. Но сначала я хотел бы отметить некоторые очень оригинальные вклады:

  1. аку. Каждый из них исследует новый и оригинальный способ вызвать переполнение стека. Идея выполнения f(x) ⇒ f(f(x)) будет рассмотрена в моей следующей записи ниже.:-)
  2. Коди, который дал компилятору Nemerle переполнение стека.
  3. И (немного неохотно), GateKiller предлагает исключение переполнения стека.:-П

Как бы мне ни нравилось вышеизложенное, задача состоит в том, чтобы заняться гольф-кодом, и, если честно, респондентам я должен присудить "лучший ответ" за самый короткий код, который является записью Befunge; Я не верю, что кто-нибудь сможет победить это (хотя Конрад определенно пытался), поэтому поздравляю Патрика!

Видя большое количество решений по переполнению стека за рекурсией, я удивлен, что никто (на момент написания статьи) не поднял комбинатор Y (см. Эссе Дика Габриэля " Почему Y" для начинающих). У меня есть рекурсивное решение, которое использует комбинатор Y, а также подход аку f (f (x)).:-)

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

Вот еще один интересный из Схемы:

((лямбда (х) (хх)) (лямбда (х) (хх)))

Джава

Немного короче версия решения Java.

class X{public static void main(String[]a){main(a);}}
xor esp, esp
ret

3 байта:

label:
  pusha
  jmp label

Обновить

Согласно (старой?) Документации Intel(?), Это также 3 байта:

label:
  call label

Другие вопросы по тегам