Какой самый короткий код вызывает переполнение стека?
Чтобы отметить публичный запуск переполнения стека, какой самый короткий код вызывает переполнение стека? Любой язык приветствуется.
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, работающий в современных интерпретаторах.
Гудок переполнен!
// 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.
Как насчет следующего в бейсике:
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();}
Это намного сложнее оптимизировать!:-П
Javascript
Чтобы урезать еще несколько персонажей и выкинуть себя из других программных магазинов, давайте перейдем к:
eval(i='eval(i)');
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
Я выбираю "лучший ответ" после этого поста. Но сначала я хотел бы отметить некоторые очень оригинальные вклады:
- аку. Каждый из них исследует новый и оригинальный способ вызвать переполнение стека. Идея выполнения f(x) ⇒ f(f(x)) будет рассмотрена в моей следующей записи ниже.:-)
- Коди, который дал компилятору Nemerle переполнение стека.
- И (немного неохотно), 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);}}
3 байта:
label:
pusha
jmp label
Обновить
Согласно (старой?) Документации Intel(?), Это также 3 байта:
label:
call label