Введение
Вы, вероятно, знакомы с 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 ГБ (возможно, если кто-то найдет полный препроцессор Тьюринга), конкуренция будет за самый маленький источник, который создает файл, по крайней мере, такого размера (просто непрактично проверять представления, которые становятся слишком большими) ,
Ответы:
C, (14 + 15) = 29 байт источника, 17 179 875 837 (16 ГБ) байт исполняемого файла
Спасибо @viraptor за 6 байтов.
Спасибо @hvd за 2 байта и размер исполняемого файла x4.
Это определяет
main
функцию как большой массив и инициализирует ее первый элемент. Это заставляет GCC хранить весь массив в результирующем исполняемом файле.Поскольку этот массив больше 2 ГБ, нам необходимо предоставить
-mcmodel=medium
флаг для GCC. Дополнительные 15 байтов включены в счет согласно правилам.Не ожидайте, что этот код сделает что-нибудь приятное при запуске.
Компилировать с:
Мне потребовалось некоторое время, чтобы приступить к тестированию предложения @ hvd - и найти машину с достаточным количеством сока, чтобы справиться с ней. В конце концов я обнаружил старую непроизводительную виртуальную машину RedHat 5.6 с 10 ГБ ОЗУ, 12 ГБ подкачки и / tmp, установленную на большой локальный раздел. Версия GCC 4.1.2. Общее время компиляции около 27 минут.
источник
a
. Вы можете просто использоватьmain[1<<30]={1};
1<<30
тогда,7<<28
может быть вариант.C #, около 1 минуты для компиляции, 28MB выходной двоичный файл:
Добавление большего количества 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;} }
типе paramA
есть типX<A>.Y
.В
class X<A> { class Y : X<Y> { Y.Y y;} }
типе paramA
есть типX<X<A>.Y>.Y
.В
class X<A> { class Y : X<Y> { Y.Y.Y y;} }
типе paramA
есть типX<X<X<A>.Y>.Y>.Y
.В
class X<A,B> { class Y : X<Y,Y> { Y y;} }
типе paramA
естьX<A,B>.Y
иB
естьX<A,B>.Y
.В
class X<A> { class Y : X<Y> { Y.Y y;} }
типе paramA
есть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;} }
типе paramA
есть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 здесь вам не поможет.
источник
Y
с .Python 3, 13-байтовый источник, 9,057,900,463 байт (8,5 ГБ) .pyc-файл
Изменить : Изменил код на версию выше после того, как я понял, правила говорят, что размер вывода за 4 ГБ не имеет значения, и код для этого немного короче; Предыдущий код - и, что более важно, объяснение - можно найти ниже.
Python 3, 16-байтовый источник,> 32 ТБ .pyc-файл (если у вас достаточно памяти, места на диске и терпения)
Пояснение: 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 ГБ, а файл достаточно большой, и в данный момент мне не хочется возиться с ним.
источник
(1<<19**8,)*2
? 4 ГБ достаточно.1<<18
на своей машине (1,5 ГБ), но позже я протестирую его на Linux, где я ожидаю, что он будет работать с полными 8 ГБ (не собираюсь пробовать версию 32 ТБ!)python -m py_compile asd.py
для генерации .pyc-файл.«Шаблон Haskell» позволяет генерировать код на Haskell во время компиляции с использованием Haskell и, следовательно, является полным препроцессором Тьюринга.
Вот моя попытка, параметризованная произвольным числовым выражением
FOO
:Магия - это код внутри «сращивания»
$(...)
. Это будет выполнено во время компиляции, чтобы сгенерировать 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:
Это весит 83 байта (66 для кода на Haskell и 17 для
-XTemplateHaskell
аргумента) плюс длинаFOO
.Мы можем избежать аргумента компилятора и просто скомпилировать
ghc
, но мы должны поместить{-# LANGUAGE TemplateHaskell#-}
в начало, что увеличивает размер кода до 97 байт.Вот несколько примеров выражений
FOO
и размер получаемого двоичного файла:У меня закончилась компиляция с ОЗУ
(2^20)
.Мы также можем сделать бесконечный список, используя
repeat
вместоreplicate FOO
, но это предотвращает остановку компилятора;)источник
[...].replicate (2^10)<$>[|0|])
). Я не опытен с Хаскеллом; какие-либо советы о том, как сделать эту компиляцию?<$>
функция широко используется в Haskell, но была перенесена только в «прелюдию» (набор функций, доступных по умолчанию) в GHC 7.10. Для более ранних версий вы должны будете добавитьimport Control.Applicative;
после существующегоimport
заявления. Я только что попробовал с GHC 7.8.4, и он работает.C ++, 250 + 26 = 276 байт
Это функция Аккермана, реализованная в шаблонах. Я не могу скомпилировать
h=a<4,2>::n;
на моей маленькой (6 ГБ) машине, но мне удалосьh=a<3,14>
получить 26M выходной файл. Вы можете настроить константы так, чтобы они превышали пределы вашей платформы - см. Ссылку в статье в Википедии.Требует наличия
-g
флага GCC (поскольку все символы отладки фактически занимают все пространство) и глубины шаблона больше, чем по умолчанию. Моя строка компиляции закончилась какИнформация о платформе
источник
A+B
в каждом классе, теперь я думаю об этом ...ASM, 61 байт (29 байт источника, 32 байта для флагов), 4 294 975 320 байт исполняемого файла
Компилировать с
gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold
источник
1<<30
достаточно для C. Так как это ассемблер, размер указывается в байтах.as
удается передатьld
, ноld
терпит неудачу с этим .-mcmodel=medium
Кажется, даже не помогает.gold
компоновщик:gcc -fuse-ld=gold ...
компилирует / ссылки ... eek! Завершается за 1:29 (89 секунд) и имеет размер 1 073 748 000 байт.gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold
. Окончательный подсчет:4,294,975,320 bytes
с добавлением 32 дополнительных байтов к длине программы для-mcmodel=large -Wl,-fuse-ld=gold
. Стоит отметить, что заголовок неверный; источник составляет 29 байт (без добавления дополнительных флагов).1<<33
, я получил8,589,942,616
исполняемый файл байта.Вот мой ответ C от 2005 года. Если бы у вас было 16 ТБ ОЗУ, то получилось бы 16 ТБ двоичного файла (у вас его нет).
источник
Простой старый препроцессор C: 214 байтов, 5 МБ на выходе
Вдохновленный моим настоящим препроцессором провал здесь .
Эксперименты показывают, что каждый уровень
#define
s будет (как и ожидалось) сделать выход примерно в десять раз больше. Но так как этот пример занял больше часа, я никогда не переходил к «G».источник
Java, исходный код 450 + 22 = 472 байта, файл класса ~ 1 ГБ
B.java (версия для гольфа, предупреждение во время компиляции)
B.java (негольфированная версия)
компиляция
объяснение
Эта бомба использует процессоры аннотаций. Нужно 2 прохода для компиляции. Первый проход строит класс процессора
B
. Во время второго прохода процессор создает новый исходный файлC.java
и компилирует его вC.class
с размером1,073,141,162
байтов.Есть несколько ограничений при попытке создать большой файл класса:
error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool
.error: too many constants
.class
файла. Если я увеличу16380
до16390
в приведенном выше коде, компилятор никогда не вернется..java
файла. Увеличение16380
до16400
в приведенном выше коде приводит к: сAn exception has occurred in the compiler (1.8.0_66). Please file a bug ...
последующимjava.lang.IllegalArgumentException
.источник
try..finally
(код в блоке finally дублируется для нормальных и исключительных случаев) и блок инициализатора (код из блока инициализатора добавляется к каждому конструктору)ä
наi
и скорректировал цифры. Теперь бомба должна создать класс 1 ГБ в любой системе без проблем с кодированием. Однако теперь ему нужно гораздо больше памяти.C, 26-байтовый источник, 2 139 103 367 байт, допустимая программа
Скомпилировано с использованием:
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.
источник
Бу , 71 байт. Время компиляции: 9 минут. Исполняемый файл 134,222,236 байт
Использует макрос
R
(для повторения), чтобы заставить компилятор умножить оператор приращения произвольное число раз. Никаких специальных флагов компилятора не требуется; просто сохраните файл какbomb.boo
и вызовите компиляторbooc bomb.boo
для его сборки.источник
2**e
-что это? Попробуй9**e
!Kotlin , 90-байтовый источник, 177416 байт (173 КБ), скомпилированный двоичный файл JVM
Технически, вы можете сделать это еще дольше, вложив выражение дальше. Однако компилятор вылетает с
StackOverflow
ошибкой, если вы увеличиваете рекурсию.источник
C ++, 214 байт (специальных параметров компиляции не требуется)
Это довольно простая двумерная рекурсия шаблонов (глубина рекурсии определяется как квадратный корень из общего числа выпущенных шаблонов, поэтому не превышает пределов платформы) с небольшим количеством статических данных в каждом.
Сгенерированный объектный файл
g++ 4.9.3 x86_64-pc-cygwin
имеет размер 2567355421 байт (2,4 ГБ).Увеличение начального значения выше 80 нарушает работу ассемблера cygwin gcc (слишком много сегментов).
Кроме того,
99999
может быть заменен9<<19
или подобен для увеличения размера без изменения исходного кода ... но я не думаю, что мне нужно больше места на диске, чем у меня уже есть;)источник
-c
для остановки компоновщика нужен флаг компиляции (2 дополнительных байта), и я не уверен, что могу принять вывод .o (не один из тех, что я перечислил). Все-таки мне это нравится, поэтому +1.Scala - источник 70 байт, результат 22980842 байт (после фляги)
В результате получается 9 5 (около 59 000) файлов специализированных классов, которые упаковываются в банку размером около 23 МБ. В принципе, вы можете продолжать, если у вас есть файловая система, которая может обрабатывать столько файлов и достаточно памяти.
(Если должна быть включена команда jar, это 82 байта.)
источник
error: java.lang.OutOfMemoryError: GC overhead limit exceeded
. Не могли бы вы также документировать необходимые команды для компиляции?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.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
С, 284 байта + 2 для
-c
ingcc bomb.c -o bomb.o -c
; вывод: 2 147 484 052 байтаисточник
Бу, намного больше, чем вы можете ожидать от этого
источник
Python 3:
Тетрационная бомба
источник