Построить бомбу компилятора


372

Введение

Вы, вероятно, знакомы с zip-бомбами , XML-бомбами и т. Д. Проще говоря, это (относительно) небольшие файлы, которые дают огромный результат при интерпретации наивным программным обеспечением. Задача здесь заключается в том, чтобы так же злоупотреблять компилятором.

Вызов

Напишите некоторый исходный код, который занимает 512 байт или меньше и который компилируется в файл, который занимает максимально возможное пространство. Самый большой выходной файл выигрывает!

правила

Итак, есть несколько важных уточнений, определений и ограничений;

  • Выходными данными компиляции должны быть файл ELF , исполняемый файл Windows (.exe) или виртуальный байт-код для JVM или CLR .Net (другие типы виртуальных байт-кодов также могут быть в порядке, если их попросить). Обновление: вывод Python в .pyc / .pyo также имеет значение .
  • Если выбранный вами язык не может быть скомпилирован непосредственно в один из этих форматов, то также разрешена транспиляция с последующей компиляцией ( Обновление: вы можете переносить несколько раз, только если вы никогда не используете один и тот же язык более одного раза ).
  • Ваш исходный код может состоять из нескольких файлов и даже файлов ресурсов, но суммарный размер всех этих файлов не должен превышать 512 байт.
  • Вы не можете использовать другие входные данные, кроме вашего исходного файла (ов) и стандартной библиотеки вашего языка по вашему выбору. Статическое связывание стандартных библиотек в порядке, если оно поддерживается. В частности, нет сторонних библиотек или библиотек ОС.
  • Должна быть возможность вызвать компиляцию с помощью команды или серии команд. Если при компиляции вам требуются определенные флаги, они учитываются в пределах вашего байтового предела (например, если у вас есть строка компиляции gcc bomb.c -o bomb -O3 -lm, -O3 -lmбудет подсчитана часть (7 байт) (обратите внимание, что начальный пробел не учитывается).
  • Препроцессоры разрешены, только если они являются стандартным вариантом компиляции для вашего языка.
  • Окружение зависит от вас, но в интересах обеспечения возможности проверки этого, пожалуйста, придерживайтесь последних (то есть доступных) версий компилятора и операционных систем (и, очевидно, укажите, что вы используете).
  • Он должен компилироваться без ошибок (с предупреждениями все в порядке), и сбой компилятора ничего не значит.
  • То, что на самом деле делает ваша программа, не имеет значения, хотя и не может быть вредоносным. Это даже не должно быть в состоянии начать.

Пример 1

Программа C

main(){return 1;}

Скомпилировано с Apple LLVM version 7.0.2 (clang-700.1.81)OS X 10.11 (64-разрядная версия):

clang bomb.c -o bomb -pg

Создает файл размером 9228 байт. Общий размер источника составляет 17 + 3 (для -pg) = 20 байт, что легко находится в пределах ограничения по размеру.

Пример 2

Программа Brainfuck:

++++++[->++++++++++++<]>.----[--<+++>]<-.+++++++..+++.[--->+<]>-----.--
-[-<+++>]<.---[--->++++<]>-.+++.------.--------.-[---<+>]<.[--->+<]>-.

Транспортируется с помощью awib на c:

./awib < bomb.bf > bomb.c

Затем скомпилировано Apple LLVM version 7.0.2 (clang-700.1.81)в OS X 10.11 (64-разрядная версия):

clang bomb.c

Создает файл размером 8464 байта. Общий ввод здесь составляет 143 байта (поскольку @lang_cпо умолчанию для awib его не нужно добавлять в исходный файл, и нет никаких специальных флагов ни для одной из команд).

Также обратите внимание, что в этом случае размер временного файла bomb.c составляет 802 байта, но это не учитывает ни исходный размер, ни выходной размер.

Финальная нота

Если будет получен вывод более 4 ГБ (возможно, если кто-то найдет полный препроцессор Тьюринга), конкуренция будет за самый маленький источник, который создает файл, по крайней мере, такого размера (просто непрактично проверять представления, которые становятся слишком большими) ,


Если используется транспортер, должен ли исходный код вывода быть менее 512 байт, а также входной исходный код?
трихоплакс

3
Допускается ли повторная транспиляция?
orlp

3
@ LegionMammal978 да, он должен производить один из указанных мной типов файлов. Но если вы думаете, что нашли что-то, что является более виртуальной машиной, чем интерпретируемым языком, спросите об этом конкретно, и возможно, я позволю это (это немного субъективно, поэтому я хотел быть очень ограничительным, чтобы начать, с опцией его открытия)
Дейв

3
@trichoplax Я не знал об этом, но из некоторого прочтения это выглядит как да; компиляция в байт-код Python абсолютно считается. Таким образом, для python размер вывода будет суммой общего размера всех ваших файлов pyc / pyo. Я скоро обновлю вопрос этими обновлениями на основе комментариев.
Дейв

2
@MartinRosenau - WGroleau уже задавал подобный вопрос; Стандартно в задачах кодирования можно использовать все, что уже существовало на момент начала задачи.
Дэйв

Ответы:


441

C, (14 + 15) = 29 байт источника, 17 179 875 837 (16 ГБ) байт исполняемого файла

Спасибо @viraptor за 6 байтов.

Спасибо @hvd за 2 байта и размер исполняемого файла x4.

Это определяет mainфункцию как большой массив и инициализирует ее первый элемент. Это заставляет GCC хранить весь массив в результирующем исполняемом файле.

Поскольку этот массив больше 2 ГБ, нам необходимо предоставить -mcmodel=mediumфлаг для GCC. Дополнительные 15 байтов включены в счет согласно правилам.

main[-1u]={1};

Не ожидайте, что этот код сделает что-нибудь приятное при запуске.

Компилировать с:

gcc -mcmodel=medium cbomb.c -o cbomb

Мне потребовалось некоторое время, чтобы приступить к тестированию предложения @ hvd - и найти машину с достаточным количеством сока, чтобы справиться с ней. В конце концов я обнаружил старую непроизводительную виртуальную машину RedHat 5.6 с 10 ГБ ОЗУ, 12 ГБ подкачки и / tmp, установленную на большой локальный раздел. Версия GCC 4.1.2. Общее время компиляции около 27 минут.

Из-за загрузки ЦП и ОЗУ я рекомендую не делать эту компиляцию на любой машине, связанной с производством .



13
Я играю против своего решения здесь, но ... тебе не нужно a. Вы можете просто использоватьmain[1<<30]={1};
viraptor

38
Боже мой Это зло X заморозился на несколько минут, пытаясь скомпилировать этот код. Я начал искать другой компьютер, который, возможно, вернул ssh и убил процесс gcc, прежде чем он наконец вернулся к жизни. Btw. Если вы хотите большее значение, чем 1<<30тогда, 7<<28может быть вариант.
kasperd

33
> 4gb? Это быстро обострилось
Уэйн Вернер

18
В случае, если кому-то еще интересно, почему это компилируется: stackoverflow.com/questions/34764796/…
TC

206

C #, около 1 минуты для компиляции, 28MB выходной двоичный файл:

class X<A,B,C,D,E>{class Y:X<Y,Y,Y,Y,Y>{Y.Y.Y.Y.Y.Y.Y.Y.Y y;}}

Добавление большего количества Y увеличит размер в геометрической прогрессии.

Объяснение Pharap по запросу @Odomontois:

Этот ответ злоупотребляет параметрами наследования и типа для создания рекурсии. Чтобы понять, что происходит, проще сначала упростить проблему. Рассмотрим class X<A> { class Y : X<Y> { Y y; } }, который генерирует общий класс X<A>, который имеет внутренний класс Y. X<A>.Yнаследует X<Y>, следовательно, X<A>.Yтакже имеет внутренний класс Y, который затем X<A>.Y.Y. В этом случае также имеется внутренний класс Y, и у этого внутреннего класса Yесть внутренний класс Yи т. Д. Это означает, что вы можете использовать область разрешения ( .) до бесконечности, и каждый раз, когда вы его используете, компилятор должен выводить другой уровень наследования и параметризацию типа. ,

При добавлении дополнительных параметров типа работа, которую должен выполнять компилятор на каждом этапе, дополнительно увеличивается.

Рассмотрим следующие случаи:
В class X<A> { class Y : X<Y> { Y y;} }типе param Aесть тип X<A>.Y.
В class X<A> { class Y : X<Y> { Y.Y y;} }типе param Aесть тип X<X<A>.Y>.Y.
В class X<A> { class Y : X<Y> { Y.Y.Y y;} }типе param Aесть тип X<X<X<A>.Y>.Y>.Y.
В class X<A,B> { class Y : X<Y,Y> { Y y;} }типе param Aесть X<A,B>.Yи Bесть X<A,B>.Y.
В class X<A> { class Y : X<Y> { Y.Y y;} }типе param Aесть X<X<A,B>.Y, X<A,B>.Y>.Yи Bесть X<X<A,B>.Y, X<A,B>.Y>.Y.
В class X<A> { class Y : X<Y> { Y.Y.Y y;} }типе param Aесть X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Yи Bесть X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y.

После этой модели, можно представить только 1 работы компилятор должен сделать , чтобы вывести , что Aк Eв Y.Y.Y.Y.Y.Y.Y.Y.Yв определении class X<A,B,C,D,E>{class Y:X<Y,Y,Y,Y,Y>{Y.Y.Y.Y.Y.Y.Y.Y.Y y;}}.

1 Вы можете понять это, но вам нужно много терпения, и intellisense здесь вам не поможет.


14
Это больше похоже на то безумие, которое я ожидал! Похоже, я ухожу, чтобы переустановить Mono…
Дейв

31
Можете ли вы дать объяснение такого пресловутого эффекта?
Одомонтуа

16
+1 за выполнение больше, чем просто инициализация большого массива.
Стиг Хеммер

6
Вот пример использования Try Roslyn и всего 3 Yс .
Коби

10
Я увидел этот вопрос и сразу подумал о тебе. Приятно!
Эрик Липперт

154

Python 3, 13-байтовый источник, 9,057,900,463 байт (8,5 ГБ) .pyc-файл

(1<<19**8,)*2

Изменить : Изменил код на версию выше после того, как я понял, правила говорят, что размер вывода за 4 ГБ не имеет значения, и код для этого немного короче; Предыдущий код - и, что более важно, объяснение - можно найти ниже.


Python 3, 16-байтовый источник,> 32 ТБ .pyc-файл (если у вас достаточно памяти, места на диске и терпения)

(1<<19**8,)*4**7

Пояснение: Python 3 делает постоянное сворачивание, и вы быстро получаете большие числа с экспонентой. Формат, используемый в файлах .pyc, хранит длину целочисленного представления с использованием 4 байтов, хотя в действительности ограничение кажется более похожим 2**31, поэтому при использовании только экспоненты для генерации одного большого числа ограничение, как представляется, создает 2 ГБ. PyC-файл из 8-байтового источника. ( 19**8немного стесняется 8*2**31, поэтому 1<<19**8имеет двоичное представление чуть менее 2 ГБ; умножение на восемь происходит потому, что нам нужны байты, а не биты)

Тем не менее, кортежи также являются неизменяемыми, и умножение кортежа также постоянно сворачивается, поэтому мы можем дублировать этот двоичный объект объемом 2 ГБ столько раз, сколько мы хотим, по крайней мере, до 2**31, вероятно, раз. 4**7, Чтобы добраться до 32 Тб был выбран только потому , что это был первый показатель я мог бы найти , что побить предыдущий 16TB ответ.

К сожалению, с памятью, которая у меня есть на моем собственном компьютере, я мог проверить это только с множителем 2, т.е. (1<<19**8,)*2, который сгенерировал файл объемом 8,5 ГБ, который, я надеюсь, демонстрирует реалистичность ответа (т. е. размер файла не ограничен 2 ** 32 = 4 ГБ).

Кроме того, я понятия не имею, почему размер файла, который я получил при тестировании, составлял 8,5 ГБ вместо ожидаемого 4 ГБ, а файл достаточно большой, и в данный момент мне не хочется возиться с ним.


2
+1, а почему нет (1<<19**8,)*2? 4 ГБ достаточно.
Akangka

2
@ChristianIrwan: Да, я забыл это правило, только осознал его несколько минут назад и еще не понял, какое редактирование мне следует сделать. :-)
Алекси Торхамо

1
Приятно. Так как это всего 13 байтов, у нас наконец есть претендент на первый ответ! Я смог подтвердить только 1<<18на своей машине (1,5 ГБ), но позже я протестирую его на Linux, где я ожидаю, что он будет работать с полными 8 ГБ (не собираюсь пробовать версию 32 ТБ!)
Дейв

1
@Dave: точный размер может зависеть от версии (1,5 ГБ звучит странно, несмотря ни на что); Я использовал Python 3.3.5 и использовал python -m py_compile asd.pyдля генерации .pyc-файл.
Алекси Торхамо

3
IIRC, python использует 30 бит на 32-битное слово в своем целочисленном представлении

130

Если будет получен вывод более 4 ГБ (возможно, если кто-то найдет полный препроцессор Тьюринга), то конкуренция будет за самый маленький источник, который создает файл, по крайней мере, такого размера (просто непрактично проверять представления, которые становятся слишком большими) ,

«Шаблон Haskell» позволяет генерировать код на Haskell во время компиляции с использованием Haskell и, следовательно, является полным препроцессором Тьюринга.

Вот моя попытка, параметризованная произвольным числовым выражением FOO:

import Language.Haskell.TH;main=print $(ListE .replicate FOO<$>[|0|])

Магия - это код внутри «сращивания» $(...). Это будет выполнено во время компиляции, чтобы сгенерировать AST на Haskell, который внедряется в AST программы вместо соединения.

В этом случае мы создаем простой AST, представляющий литерал 0, мы повторяем это FOOвремя, чтобы создать список, а затем используем его ListEиз Language.Haskell.THмодуля, чтобы превратить этот список AST в один большой AST, представляющий литерал [0, 0, 0, 0, 0, ...].

Полученная программа эквивалентна main = print [0, 0, 0, ...]с FOOповторениями 0.

Чтобы скомпилировать в ELF:

$ ghc -XTemplateHaskell big.hs
[1 of 1] Compiling Main             ( big.hs, big.o )
Linking big ...
$ file big
big: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /nix/store/mibabdfiaznqaxqiy4bqhj3m9gaj45km-glibc-2.21/lib/ld-linux.so.2, for GNU/Linux 2.6.32, not stripped

Это весит 83 байта (66 для кода на Haskell и 17 для -XTemplateHaskellаргумента) плюс длина FOO.

Мы можем избежать аргумента компилятора и просто скомпилировать ghc, но мы должны поместить {-# LANGUAGE TemplateHaskell#-}в начало, что увеличивает размер кода до 97 байт.

Вот несколько примеров выражений FOOи размер получаемого двоичного файла:

FOO         FOO size    Total size    Binary size
-------------------------------------------------
(2^10)      6B          89B           1.1MB
(2^15)      6B          89B           3.6MB
(2^17)      6B          89B           12MB
(2^18)      6B          89B           23MB
(2^19)      6B          89B           44MB

У меня закончилась компиляция с ОЗУ (2^20).

Мы также можем сделать бесконечный список, используя repeatвместо replicate FOO, но это предотвращает остановку компилятора;)


46
Добро пожаловать в Программирование головоломок и Code Golf. Это блестящий ответ, особенно для нового пользователя на этом сайте. Если вам нужна помощь (в чем я сомневаюсь), не стесняйтесь спрашивать.
wizzwizz4

3
@ wizzwizz4: Да, это блестящий ответ. По сути, он такой же, как у меня, за исключением того, что в Haskell требуется специальная директива компилятора, чтобы заставить работать метапрограммирование. ;)
Мейсон Уилер

2
Когда я компилирую с GHC 7.8.3, я получаю «Not in scope: '<$>'» (я установил код в [...].replicate (2^10)<$>[|0|])). Я не опытен с Хаскеллом; какие-либо советы о том, как сделать эту компиляцию?
Дэйв

38
Жаль, что шаблон haskell не достаточно ленив для потоковой передачи бесконечного исполняемого файла.
PyRulez

1
Привет @Dave <$>функция широко используется в Haskell, но была перенесена только в «прелюдию» (набор функций, доступных по умолчанию) в GHC 7.10. Для более ранних версий вы должны будете добавить import Control.Applicative;после существующего importзаявления. Я только что попробовал с GHC 7.8.4, и он работает.
Варбо

80

C ++, 250 + 26 = 276 байт

template<int A,int B>struct a{static const int n;};
template<int A,int B>const int a<A,B>::n=a<A-1,a<A,B-1>::n>::n;
template<int A>struct a<A,0>{static const int n=a<A-1,1>::n;};
template<int B>struct a<0,B>{static const int n=B+1;};
int h=a<4,2>::n;

Это функция Аккермана, реализованная в шаблонах. Я не могу скомпилировать h=a<4,2>::n;на моей маленькой (6 ГБ) машине, но мне удалось h=a<3,14>получить 26M выходной файл. Вы можете настроить константы так, чтобы они превышали пределы вашей платформы - см. Ссылку в статье в Википедии.

Требует наличия -gфлага GCC (поскольку все символы отладки фактически занимают все пространство) и глубины шаблона больше, чем по умолчанию. Моя строка компиляции закончилась как

g++ -ftemplate-depth=999999 -g -c -o 69189.o 69189.cpp

Информация о платформе

g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Linux 3.13.0-46-generic #79-Ubuntu SMP x86_64 GNU/Linux

Мне очень нравится этот, но я не уверен, что могу принять вывод .o, так как я сказал ELF / .exe / etc. (и компиляция этого полностью оптимизирует все это!). Тем не менее, +1 (и подтвердил)
Дейв

4
Обновление: Как Бен Фойгт указывает на его ответ, GCC на Linux делает генерировать ELF файлы как .o выход, и я был в состоянии подтвердить вариант <3,14> с ним, так что да - это верно.
Дэйв

17
Я ожидал чего-то абсурдного из шаблонов C ++. Я не ожидал функции Аккермана.
Марк

не даст ли Фибоначчи меньший код и лучший контроль размера вывода?
Уилл Несс

1
Но мы хотим больше кода! Фибоначчи дает почти такой же размер, как чистый линейный код (но более длительное время компиляции, чем линейный). Вы могли бы, конечно, повеселиться со статическим массивом размера A+Bв каждом классе, теперь я думаю об этом ...
Тоби Спейт

65

ASM, 61 байт (29 байт источника, 32 байта для флагов), 4 294 975 320 байт исполняемого файла

.globl main
main:
.zero 1<<32

Компилировать с gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold


5
1<<30достаточно для C. Так как это ассемблер, размер указывается в байтах.
Вираптор

2
@viraptor В моей системе 32 ГБ ОЗУ, и я попытался создать твой код. asудается передать ld, но ldтерпит неудачу с этим . -mcmodel=mediumКажется, даже не помогает.
Iwillnotexist Idonotexist

2
попробуйте принудительно использовать goldкомпоновщик: gcc -fuse-ld=gold ...компилирует / ссылки ... eek! Завершается за 1:29 (89 секунд) и имеет размер 1 073 748 000 байт.
Lornix

2
Я наконец получил это, чтобы собрать на 64-битной Ubuntu 15.10, с вызовом gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold. Окончательный подсчет: 4,294,975,320 bytesс добавлением 32 дополнительных байтов к длине программы для -mcmodel=large -Wl,-fuse-ld=gold. Стоит отметить, что заголовок неверный; источник составляет 29 байт (без добавления дополнительных флагов).
Mego

3
Увеличив выделение 1<<33, я получил 8,589,942,616исполняемый файл байта.
Mego

60

Вот мой ответ C от 2005 года. Если бы у вас было 16 ТБ ОЗУ, то получилось бы 16 ТБ двоичного файла (у вас его нет).

struct indblock{
   uint32_t blocks[4096];
};

struct dindblock {
    struct indblock blocks[4096];
};

struct tindblock {
    struct dindblock blocks[4096];
};

struct inode {
    char data[52]; /* not bothering to retype the details */
    struct indblock ind;
    struct dindblock dint;
    struct tindblock tind;
};

struct inode bbtinode;

int main(){}

19
Msgstr "Произвел бы бинарный файл 16 ТБ, если бы у вас было 16 ТБ ОЗУ (у вас его нет)." - у меня нет жесткого диска 16 ТБ! Я не могу проверить это, но, тем не менее, это круто.
Дэйв

5
Я обнаружил это случайно и наблюдал, как компилятор опрокидывался, когда у него заканчивалось адресное пространство.
Джошуа

8
Пожалуйста, НЕ пытайтесь сыграть в гольф в этой записи; игра в гольф наносит удар по замыслу примера кода, и в любом случае это не дает никаких преимуществ. Код уже GPL'd по состоянию на 2005 год.
Джошуа

6
@BenVoigt Несмотря на это, редактирование чужого кода здесь никогда не допустимо. Оставьте комментарий, если есть проблема. Соответствующее сообщение мета: meta.codegolf.stackexchange.com/questions/1615/…
Mego

2
@ Джошуа: Проверьте разницу уценки. Мего только добавил подсвечивающий намек.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

25

Простой старый препроцессор C: 214 байтов, 5 МБ на выходе

Вдохновленный моим настоящим препроцессором провал здесь .

#define A B+B+B+B+B+B+B+B+B+B
#define B C+C+C+C+C+C+C+C+C+C
#define C D+D+D+D+D+D+D+D+D+D
#define D E+E+E+E+E+E+E+E+E+E
#define E F+F+F+F+F+F+F+F+F+F
#define F x+x+x+x+x+x+x+x+x+x

int main(void) { int x, y = A; }

Эксперименты показывают, что каждый уровень #defines будет (как и ожидалось) сделать выход примерно в десять раз больше. Но так как этот пример занял больше часа, я никогда не переходил к «G».


9
Это что-то вроде бомбы XML
наушник

9
В частности, это реализация оригинального "Миллиарда смеха".
mynxomaτ

Это безумие, но все же просто.
Вахид Амири

2
Вау, это на самом деле вызывает segfault в GCC 4.9 и Clang. Какой компилятор вы использовали?
Дэйв

1
@Dave: Странно. Когда я компилирую, используя make, он компилируется, но если я ввожу ту же самую команду, которая использует make, он вылетает. И это, похоже, не связано с переменными среды.
Томас Падрон-Маккарти

24

Java, исходный код 450 + 22 = 472 байта, файл класса ~ 1 ГБ

B.java (версия для гольфа, предупреждение во время компиляции)

import javax.annotation.processing.*;@SupportedAnnotationTypes("java.lang.Override")public class B extends AbstractProcessor{@Override public boolean process(java.util.Set a,RoundEnvironment r){if(a.size()>0){try(java.io.Writer w=processingEnv.getFiler().createSourceFile("C").openWriter()){w.write("class C{int ");for(int i=0;i<16380;++i){for(int j=0;j<65500;++j){w.write("i");}w.write(i+";int ");}w.write("i;}");}catch(Exception e){}}return true;}}

B.java (негольфированная версия)

import java.io.Writer;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes("java.lang.Override")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class B extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (annotations.size() > 0) {
            try (Writer writer = processingEnv.getFiler().createSourceFile("C").openWriter()) {
                writer.write("class C{int ");
                for (int i = 0; i < 16380; ++i) {
                    for (int j = 0; j < 65500; ++j) {
                        writer.write("i");
                    }
                    writer.write(i + ";int ");
                }
                writer.write("i;}");
            } catch (Exception e) {
            }
        }
        return true;
    }
}

компиляция

javac B.java
javac -J-Xmx16G -processor B B.java

объяснение

Эта бомба использует процессоры аннотаций. Нужно 2 прохода для компиляции. Первый проход строит класс процессора B. Во время второго прохода процессор создает новый исходный файл C.javaи компилирует его вC.class с размером1,073,141,162 байтов.

Есть несколько ограничений при попытке создать большой файл класса:

  • Создание идентификаторов длиной более 64 КБ приводит к: error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool .
  • Создание более чем 64 тыс. Переменных / функций приводит к: error: too many constants
  • Существует также ограничение в размере около 64 КБ для размера кода функции.
  • Похоже, что в компиляторе java есть общий предел (ошибка?) Около 1 ГБ для .classфайла. Если я увеличу 16380до16390 в приведенном выше коде, компилятор никогда не вернется.
  • Существует также ограничение в 1 ГБ для .javaфайла. Увеличение 16380до 16400в приведенном выше коде приводит к: с An exception has occurred in the compiler (1.8.0_66). Please file a bug ...последующим java.lang.IllegalArgumentException.

10
Аккуратный; вы по сути сделали свой собственный препроцессор в пределах ограничения по размеру на языке с компилятором, который изначально поддерживает пользовательские препроцессоры. Это в рамках правил. Последний класс для меня был только 0,5 ГБ, но я могу подтвердить метод.
Дэйв

Другой пример в Java habrahabr.ru/post/245333 - он использует вложенный try..finally(код в блоке finally дублируется для нормальных и исключительных случаев) и блок инициализатора (код из блока инициализатора добавляется к каждому конструктору)
Виктор

Я заменил äна iи скорректировал цифры. Теперь бомба должна создать класс 1 ГБ в любой системе без проблем с кодированием. Однако теперь ему нужно гораздо больше памяти.
Sleafar

? расширяет TypeElement?!?
кот

1
@cat Смотрите здесь: angelikalanger.com/GenericsFAQ/FAQSections/…
Sleafar

22

C, 26-байтовый источник, 2 139 103 367 байт, допустимая программа

const main[255<<21]={195};

Скомпилировано с использованием: gcc cbomb.c -o cbomb(gcc версии 4.6.3, Ubuntu 12.04, ~ 77 секунд)

Я подумала, что попытаюсь увидеть, насколько велика я могла бы создать правильную программу без использования каких-либо параметров командной строки. Я получил идею из этого ответа: https://codegolf.stackexchange.com/a/69193/44946 от Digital Trauma. Смотрите комментарии там, почему это компилируется.

Как это работает: The constубирает флаг записи со страниц в сегменте, поэтому можно выполнить main. 195 машинный код Intel для возврата. А поскольку архитектура Intel имеет младший порядок, это первый байт. Программа завершит работу с любым кодом запуска, записанным в регистре eax, с вероятностью 0.

Это всего около 2 гигабайт, потому что компоновщик использует 32-битные значения со знаком для смещений. Это на 8 мегабайт меньше, чем 2 гигабайта, потому что компилятору / компоновщику нужно немного места для работы, и это самое большое, что я мог получить без ошибок компоновщика - ymmv.


3
Интересно отметить, что на выходе получается 2,078,451 байт в сжатом формате с максимальным сжатием = 1029: 1 степень сжатия.
Закипу

20

Бу , 71 байт. Время компиляции: 9 минут. Исполняемый файл 134,222,236 байт

macro R(e as int):
 for i in range(2**e):yield R.Body
x = 0
R 25:++x

Использует макрос R(для повторения), чтобы заставить компилятор умножить оператор приращения произвольное число раз. Никаких специальных флагов компилятора не требуется; просто сохраните файл как bomb.booи вызовите компилятор booc bomb.booдля его сборки.


2**e-что это? Попробуй 9**e!
wchargin

1
@WChargin: Самое интересное в метапрограммировании - это то, как легко вы можете его настроить!
Мейсон Уилер

У меня возникли проблемы с установкой бу ... Я подтвердлю это, когда мне удастся установить его!
Дэйв

@Dave Какие у тебя проблемы с этим?
Мейсон Уилер

16

Kotlin , 90-байтовый источник, 177416 байт (173 КБ), скомпилированный двоичный файл JVM

inline fun a(x:(Int)->Any){x(0);x(1)}
fun b()=a{a{a{a{a{a{a{a{a{a{a{println(it)}}}}}}}}}}}

Технически, вы можете сделать это еще дольше, вложив выражение дальше. Однако компилятор вылетает с StackOverflowошибкой, если вы увеличиваете рекурсию.


Ваши префиксы SI не согласны. Это 177416 килобайт = 173 МБ или 177416 байт = 173 КБ?
Бен Фойгт

1
@BenVoigt Спасибо, что указали на это: D
TheNumberOne

Впечатляет, есть +1
J Аткин

Для компиляции Kotlin 1.2.20 нам нужно удалить одну глубину, и она составляет ~ 104 КБ. Какую версию вы использовали изначально?
TWiStErRob

15

C ++, 214 байт (специальных параметров компиляции не требуется)

#define Z struct X
#define T template<int N
T,int M=N>Z;struct Y{static int f(){return 0;}};T>Z<N,0>:Y{};T>Z<0,N>:Y{};T,int M>Z{static int f(){static int x[99999]={X<N-1,M>::f()+X<N,M-1>::f()};}};int x=X<80>::f();

Это довольно простая двумерная рекурсия шаблонов (глубина рекурсии определяется как квадратный корень из общего числа выпущенных шаблонов, поэтому не превышает пределов платформы) с небольшим количеством статических данных в каждом.

Сгенерированный объектный файл g++ 4.9.3 x86_64-pc-cygwinимеет размер 2567355421 байт (2,4 ГБ).

Увеличение начального значения выше 80 нарушает работу ассемблера cygwin gcc (слишком много сегментов).

Кроме того, 99999может быть заменен 9<<19или подобен для увеличения размера без изменения исходного кода ... но я не думаю, что мне нужно больше места на диске, чем у меня уже есть;)


Подтверждено (на самом деле это 2,56 ГБ с clang), но -cдля остановки компоновщика нужен флаг компиляции (2 дополнительных байта), и я не уверен, что могу принять вывод .o (не один из тех, что я перечислил). Все-таки мне это нравится, поэтому +1.
Дэйв

@Dave: gcc .o файлы в формате ELF, не так ли?
Бен Фойгт

Точно сказать не могу. Они не начинаются с магического числа ELF, когда я их сгенерирую ... Я расскажу позже.
Дэйв

@Dave: Ну, Cygwin GCC не генерирует файл ELF. Linux gcc кажется (хотя я смотрю на один из другого куска кода)
Бен Фойгт

Да, GCC 5.2.1 на Kubuntu действительно генерирует файл ELF, но он занимает всего 9 МБ! Не уверен, как это удалось сжать так сильно по сравнению с другими компиляторами. Возможно, GCC 4.9 сделает файл ELF объемом 2 ГБ.
Дэйв

6

Scala - источник 70 байт, результат 22980842 байт (после фляги)

import scala.{specialized => s}
class X[@s A, @s B, @s C, @s D, @s E]

В результате получается 9 5 (около 59 000) файлов специализированных классов, которые упаковываются в банку размером около 23 МБ. В принципе, вы можете продолжать, если у вас есть файловая система, которая может обрабатывать столько файлов и достаточно памяти.

(Если должна быть включена команда jar, это 82 байта.)


Я не мог скомпилировать это error: java.lang.OutOfMemoryError: GC overhead limit exceeded. Не могли бы вы также документировать необходимые команды для компиляции?
Петр

@ P.Péter - Вы должны дать компилятору больше памяти, например, scalac -J-Xmx12G X.scalaэто то, что я использовал. Я не проверял, сколько на самом деле нужно.
Рекс Керр

все еще не компилируется, к сожалению :( error: error while loading AnnotatedElement, class file '/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar(java/lang/reflect/AnnotatedElement.class)' is broken (bad constant pool tag 18 at byte 76) one error foundМожете ли вы указать версию scala и java (может быть, и платформу)? Я использовал scalac 2.9.2 и OpenJDK 1.8.0_66-internal-b17, на debian 8 x86-64.
P.Péter

Ubuntu 15,10, java version "1.8.0_72-ea" Java(TM) SE Runtime Environment (build 1.8.0_72-ea-b05) Java HotSpot(TM) 64-Bit Server VM (build 25.72-b05, mixed mode) ,$ scala -version Scala code runner version 2.11.7 -- Copyright 2002-2013, LAMP/EPFL
Rex Керр

2

С, 284 байта + 2 для -cin gcc bomb.c -o bomb.o -c; вывод: 2 147 484 052 байта

#define a 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
#define b a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a
#define c b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b
#define d c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c
#define e d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
#define f e,e,e,e,e,e,e,e,e,e,e,e,e,e,e,e
__int128 x[]={f,f,f,f,f,f,f,f};

0

Бу, намного больше, чем вы можете ожидать от этого

macro R(e as int):for i in range(9**e):yield R.Body
x = 0
R 99:++x

Это похоже на ответ Мейсона Уилера с небольшими изменениями (??). Достигли ли вы того же ответа самостоятельно или в измененных вами значениях есть что-то важное (если да, отредактируйте ответ, чтобы объяснить, почему они важны).
Дейв

0

Python 3:

9**9**9**9**9

Тетрационная бомба


2
Вы должны указать, сколько байтов составляет вывод, чтобы увидеть, как ваша запись сравнивается с другими.
Sanchises

Добро пожаловать в PPCG! Кажется, вы случайно создали две учетные записи и опубликовали этот ответ дважды. Я удалил другой ответ. Как сказал Санчисес, эта задача оценивается размером скомпилированной программы . Таким образом, вы должны включить этот размер в свой ответ, так как это основной балл. Также обратите внимание, что реальная программа не будет очень большой, только выражение, которое вы создаете в памяти, поэтому вы можете подумать о другом подходе.
Мартин Эндер,

1
@MartinEnder из-за того, как Python вычисляет некоторые выражения во время компиляции и сохраняет числа с произвольной точностью, это (теоретически) будет иметь довольно большой исполняемый файл. Но, как заметил Алекси Торхамо (который использовал ту же технику для части своего ответа), это ограничение составляет где-то около 2 ГБ, поэтому я ожидаю, что этот код при написании, вероятно, не скомпилируется (хотя я не проверял ). Если OP может заставить его скомпилировать и опубликовать скомпилированный размер (вместе с командой, необходимой для его генерации), то он действителен. Сходство с существующим ответом Алекси выглядит для меня совпадением.
Дейв
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.