Який найкоротший код може спричинити переповнення стека? [зачинено]


160

Щоб відзначити публічний запуск Stack Overflow, який найкоротший код може спричинити переповнення стека? Будь-яка мова вітається.

ETA: Просто, щоб бути зрозумілим у цьому питанні, оскільки я є випадковим користувачем схеми: "рекурсія" - це справді ітерація, і будь-яке рішення, яке гідним компілятором може бути перетворене на ітеративне рішення порівняно тривіально. підрахувати. :-P

ETA2: я зараз вибрав "найкращу відповідь"; дивіться цю публікацію для обґрунтування. Дякуємо всім, хто долучився! :-)

Відповіді:


212

На всі ці відповіді і без Befunge? Я б заробив справедливу суму, це найкоротше їх вирішення:

1

Не жартую. Спробуйте самі: http://www.quirkster.com/iano/js/befunge.html

EDIT: Я думаю, мені потрібно пояснити це. Операнд 1 натискає на внутрішній стек Befunge, а відсутність нічого іншого ставить його в цикл згідно з правилами мови.

Використовуючи наданий інтерпретатор, ви зрештою - а я маю на увазі - зрештою, момент, коли масив Javascript, який представляє стек Befunge, стає занадто великим, щоб браузер перерозподілив. Якби у вас був простий інтерпретатор Befunge з меншим та обмеженим стеком - як це стосується більшості мов нижче - ця програма швидше спричинить помітні переповнення.


8
Хм… але це справді переповнення стека чи просто нескінченна петля? Мій перекладач JS не переповнився, він просто пішов у відпустку, так би мовити.
Конрад Рудольф

3
Це не нескінченний цикл, тому що інструкція 1 натискає 1 на стек. Зрештою, у вашого перекладача Befunge не вистачить місця у стеці, але це займе певний час. :)
Патрік

18
Ви .. розбили мій браузер і .. відправив мого вентилятора процесора в режим проїзду.
Sam152

2
Дивовижний! Мій комп’ютер або браузер (Opera) не
вийшли з ладу,

28
Ось програма Befunge, яка переповнює швидше: " вона завантажує 79 примірників числа 32 кожні два рази, коли вона обертається, а не 2 копії числа 1.
KirarinSnow


174

Ви також можете спробувати це у C # .net

throw new StackOverflowException();

29
Педант в мені каже, що це не спричиняє переповнення жодної стеки, просто кидає виняток. Це як сказати найшвидший спосіб напасти на акул - стояти в морі і кричати "Атака акули!". Незважаючи на це, я буду його проголосувати. :)
Бернар

Ну - чи є різниця? Ви можете зловити його і продовжувати? Або це точно як stackoverflow в c #? У цьому випадку це якимось чином є потоковим потоком, оскільки його не можна відрізнити від одного ... Однак - оновлення з усіх причин вище
Пн.

18
Якщо стопка перелітає в лісі, нікого навколо не спіймати, чи це кидає виняток?

Я б не сказав "найкоротший", оскільки це не так, як ти можеш скласти однолінійку. Це робить кинути переповнення стека швидко , хоча я думаю.
Домінік К

159

Немерле :

Це збої компілятора з StackOverflowException:

def o(){[o()]}

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?FizzBuzz#x86 для деяких прикладів цього. (Я, чесно кажучи, не знаю, як люди можуть робити 99-байтні бінарні файли ELF.):
Кріс Джестер-Янг

7
@ lbrandy: Є достатньо людей, які можуть писати об'єктний код безпосередньо. Я не можу це зробити для x86, але для певного мікропроцесора можу. Я би порахував такий код.
Joey

113

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, що працює в поточних інтерпретаторах.




55

Для кожного завдання потрібен правильний інструмент. Зустріти SO Переповнення мови, оптимізований для переповнення стека продукції:

so

7
Якщо ви створюєте спеціалізовану мову для генерації переповнення з мінімальним кодом, очевидно, ви хочете (1) порожній вхід створює код переповнення стека (можливо, невеликий двійковий код, який запускає нативний код, сформований із запису коду асемблери) або (2 ) усі програми введення виробляють вказане двійкове.
Jared Updike

Гммм, не Тюрінг завершений. Я не знаю, чи могли б ви ще називати це мовою ...
Адам Девіс,

42

TeX:

\def~{~.}~

Призводить до:

! Перевищена ємність TeX, вибачте [розмір стека вводу = 5000].
~ -> ~
    .
~ -> ~
    .
~ -> ~
    .
~ -> ~
    .
~ -> ~
    .
~ -> ~
    .
...
<*> \ def ~ {~.} ~

LaTeX:

\end\end

Призводить до:

! Перевищена ємність TeX, вибачте [розмір стека вводу = 5000].
\ end # 1 -> \ csname кінець №1
                      \ endcsname \ @checkend {# 1} \ Розширювач \ endgroup \ якщо @ e ...
<*> \ end \ end

Оскільки ~він активний, його можна використовувати замість \a. І я відкрив код LaTeX зовсім випадково. :)
Джош Лі

35

Асемблер Z-80 - у місці пам'яті 0x0000:

rst 00

один байт - 0xC7 - нескінченний цикл натискання поточного ПК на стек і стрибки на адресу 0x0000.


2
Я пам'ятаю, що порожнім eprom буде всі 0xffs, що є першими 7 (= викликом 0x0038) інструкціями. Це було б корисно для налагодження апаратури за допомогою осцилографа. Адресна шина проїжджатиме через 64K простір, коли стек багато разів переповнюється, перемішуючись з читаннями 0xff від 0x0038.
Білл Форстер

29

Англійською:

recursion = n. See recursion.

32
Будь-який розумний людський мозок також буде оптимізувати тлумачення цього, а не підірвати. :-P
Кріс Єстер-Янг

73
Кріс, розумні людські мізки стають рідкістю в наші дні.
Джейсон Z

20
рідкість ... ти маєш на увазі, що вони існують?
Адам Лерман

11
Рекурсія Google
CodeFusionMobile

29

Ще один приклад PHP:

<?
require(__FILE__);

4
Вас навіть можна скоротити, пропустивши дужки (але включаючи пробіл замість першого).
алекс

26

Як щодо наступного в BASIC:

10 GOSUB 10

(У мене немає перекладача БАЗОВИХ, боюся, тому це здогад).


3
Насправді не є переповнення стека, оскільки BASIC - це мова, що не має статків. Навіть VB (у якого є стек) не переповнюватиме це, оскільки він просто стрибає, не створюючи рамку стека.
Даніель Шпієк

21
Це а GOSUB, а не GOTO. Оскільки це RETURNs, звідки його викликали, напевно він використовує стек?
Том

3
Так, я згоден. У 80-х роках у мене було багато переповнень стеків.
нік

6
Я запустив цю в ябасику просто заради задоволення, і це мало не збило мій комп'ютер. Слава богу, Маллок врешті-решт зазнав невдачі, але я завчався, як завтра.
Адам Розенфілд

2
На жаль, Адам ... нагадує мені про час в університеті, коли хтось випадково написав програму, яка рекурсивно розщедрилася: зняла весь сервер Silicon Graphics.
стусміт

26

Мені сподобалось купу відповідей Коді, тому ось мій аналогічний внесок у програмі 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
Не компілює для мене: "невизначене посилання на" головне "": P
Ендрю Джонсон

1
Я не розумію: навіщо дзвонити o () 2x?
Діна

3
@Dinah: Одним із обмежень мого змагання було те, що оптимізація хвостових викликів не вважається рекурсією; це просто ітеративна петля. Якщо ви написали o () лише один раз, це може бути зворотним викликом, оптимізованим у щось подібне (компетентним компілятором): "o: jmp o". З двома дзвінками o, компілятор повинен використовувати щось на кшталт: "o: call o; jmp o". Саме рекурсивна інструкція "виклик" робить стек переповненим.
Кріс Єстер-Янг

Ви праві - я не звертав уваги на цю частину. Дякую за роз’яснення.
Діна


17

Javascript

Щоб обрізати ще декількох персонажів і щоб нас вигнали з більшої кількості магазинів програмного забезпечення, давайте продовжимо:

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 виявляється досить дратівлива слабкість (такі хвостові дзвінки можна накреслити під час компіляції).
Даніель Шпієк

ти впевнений, що це хвіст? що випадання з кінця програми не викликає оболонку інтерпретатора?
Аарон

15

Скажіть, будь ласка, що таке абревіатура " GNU ".


4
Або Ейн (Ейн не Емак), або Цвей (Цвей був Ейн спочатку). :-P
Кріс Єстер-Янг

Або YAML, або WINE, або XNA, або будь-яке інше на en.wikipedia.org/wiki/Recursive_acronym
TM.

Drei (Drei - це справді Emacs Incognito), Fier (Fier - це Remavented Emacs) - добре, тому я просто створив це :-)
Ferruccio

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

Ось сподіваємось на відсутність рецидивів хвоста!


1
Хе-хе, смішно. Пов’язана з розмовами, ідея "ефекту камерної ехографії" теж цікава. Не зовсім стек-індукуючий перелив, але все ж.
Кріс Єстер-Янг

8
Хіба це не буде нульовим винятком покажчика? Вибачте, я знаю, що це жарт.
Джеймс

12

C - Це не найкоротше, але без рекурсії. Він також не є портативним: він виходить з ладу на Solaris, але деякі реалізації аллока () можуть повернути тут помилку (або викликати 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, і програма навіть не працює (мабуть, недостатньо аргументів!).
Ендрю Джонсон

11

perl в 12 символів:

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

баш в 10 символів (пробіл у функції важливий):

i(){ i;};i

11

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


1
Тут, у Новій Зеландії, у нас є Burger Wisconsin, де вони використовують великі, але тонкі пиріжки. Я впевнений, що ви можете скласти більше 4 таких, якщо хочете; це буде дуже дорогий гамбургер!
Кріс Єстер-Янг



11

Пітон :

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. Коді, який дав компілятору Nemerle переповнення стека.
  3. І (трохи сумно), GateKiller - про викид виключення переповнення стека. :-P

Наскільки мені подобається вищезазначене, завдання полягає в тому, щоб робити гольф з кодом, і щоб бути справедливим до респондентів, я повинен присвоїти «найкращу відповідь» за найкоротший код, який є записом Befunge; Я не вірю, що ніхто не зможе це перемогти (хоча Конрад, безумовно, намагався), тому вітаю Патріка!

Бачачи велику кількість рішень стек-переповнення за рекурсією, я здивований, що ніхто (на сьогоднішній день написання) не виховував комбінатор Y (див. Есе Діка Габріеля «Чому Y» для букваря). У мене є рекурсивне рішення, яке використовує комбінатор Y, а також підхід f (f (x)) aku. :-)

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

8

Ось ще один цікавий варіант із схеми:

((лямбда (x) (xx)) (лямбда (x) (xx)))

Дуже приємно, і в цьому є і хороша симетрія. Також використовувати рецептуру (лямбда (x) (xx)): ((Y (лямбда (x) (xx)))) #f) теж дуже весело!
Кріс Єстер-Янг

О, це гарно. Він працює і в Ruby, хоча і не такий гарний, як у Scheme: lambda {| x | x.call x} .call lambda {| x | x.call x}
Уейн Конрад

7

Java

Трохи коротша версія рішення Java.

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

5
Або (однакова кількість символів): загальнодоступний статичний недійсний основний (Рядок ... а) {main ();}
Майкл Майєрс

Або для хлопців з TDD (однакова кількість символів): public class ${@org.junit.Test public void $ () {$ ();}}
mhaller

Але все ж не найкоротший (див. Мою відповідь)
Draemon


5

3 байти:

label:
  pusha
  jmp label

Оновлення

Відповідно до (старої?) Документації Intel (?) , Це також 3 байти:

label:
  call label


Це 3 байти в 32-бітному режимі. Приємна відповідь, вважаючи, що вона заповнить стек набагато швидше, ніж моя відповідь!
Кріс Єстер-Янг

Відповідно до penguin.cz/~literakl/intel/j.html#JMP , jmp - 3 байти з 8, 16 або 32 бітовою відносною адресою призначення. Пуша також 1 байт, що складає в цілому 4
Андерс Сандвіг

Існує три типи jmp, короткий, близький і далекий. Короткий jmp (з використанням коду 0xEB) - два байти. Місце призначення має бути від -128 до 127 байт від наступної інструкції. :-)
Кріс Єстер-Янг

Можливо, ти маєш рацію. Мені занадто лінь розкопати асемблера і перевірити ...;)
Андерс Сандвіг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.