Introducción
Probablemente esté familiarizado con las bombas zip , las bombas XML , etc. En pocas palabras, son archivos (relativamente) pequeños que producen un enorme rendimiento cuando son interpretados por software ingenuo. El desafío aquí es abusar de un compilador de la misma manera.
Desafío
Escriba un código fuente que ocupa 512 bytes o menos y que se compila en un archivo que ocupa el mayor espacio posible. ¡El archivo de salida más grande gana!
Reglas
OK, entonces hay algunas aclaraciones importantes, definiciones y restricciones;
- La salida de la compilación debe ser un archivo ELF , un ejecutable portátil de Windows (.exe) o un código de bytes virtual para JVM o CLR de .Net (es probable que otros tipos de códigos de bytes virtuales también estén bien si se solicitan). Actualización: la salida .pyc / .pyo de Python también cuenta .
- Si su idioma de elección no puede compilarse directamente en uno de esos formatos, también se permite la transpilación seguida de la compilación ( Actualización: puede transpilar varias veces, siempre y cuando nunca use el mismo idioma más de una vez ).
- Su código fuente puede consistir en múltiples archivos, e incluso archivos de recursos, pero el tamaño sumado de todos estos archivos no debe exceder los 512 bytes.
- No puede utilizar ninguna otra entrada que no sea su (s) archivo (s) de origen y la biblioteca estándar de su idioma de elección. La vinculación estática de bibliotecas estándar está bien cuando es compatible. Específicamente, no hay bibliotecas de terceros o bibliotecas del sistema operativo.
- Debe ser posible invocar su compilación utilizando un comando o una serie de comandos. Si necesita indicadores específicos al compilar, estos cuentan para su límite de bytes (por ejemplo, si su línea de compilación es
gcc bomb.c -o bomb -O3 -lm
, se-O3 -lm
contará la parte (7 bytes) (tenga en cuenta que el espacio inicial no se cuenta). - Los preprocesadores solo están permitidos si son una opción de compilación estándar para su idioma.
- El entorno depende de usted, pero en aras de hacer que esto sea verificable, respete las versiones de compilador y los sistemas operativos recientes (es decir, disponibles) (y, obviamente, especifique cuál está utilizando).
- Debe compilarse sin errores (las advertencias están bien), y el bloqueo del compilador no cuenta para nada.
- Lo que su programa realmente hace es irrelevante, aunque no puede ser nada malicioso. Ni siquiera tiene que poder comenzar.
Ejemplo 1
El programa C
main(){return 1;}
Compilado con Apple LLVM version 7.0.2 (clang-700.1.81)
OS X 10.11 (64 bits):
clang bomb.c -o bomb -pg
Produce un archivo de 9228 bytes. El tamaño total de la fuente es 17 + 3 (para el -pg
) = 20 bytes, que está fácilmente dentro del límite de tamaño.
Ejemplo 2
El programa Brainfuck:
++++++[->++++++++++++<]>.----[--<+++>]<-.+++++++..+++.[--->+<]>-----.--
-[-<+++>]<.---[--->++++<]>-.+++.------.--------.-[---<+>]<.[--->+<]>-.
Transpilado con awib a c con:
./awib < bomb.bf > bomb.c
Luego compilado con Apple LLVM version 7.0.2 (clang-700.1.81)
OS X 10.11 (64 bits):
clang bomb.c
Produce un archivo de 8464 bytes. La entrada total aquí es de 143 bytes (dado que @lang_c
es el valor predeterminado para awib, no era necesario agregarlo al archivo de origen, y no hay indicadores especiales en ninguno de los comandos).
También tenga en cuenta que, en este caso, el archivo temporal bomb.c tiene 802 bytes, pero esto no tiene en cuenta ni el tamaño de origen ni el tamaño de salida.
Nota final
Si se logra una salida de más de 4 GB (tal vez si alguien encuentra un preprocesador completo), la competencia será por la fuente más pequeña que produzca un archivo de al menos ese tamaño (simplemente no es práctico probar envíos que son demasiado grandes) .
Respuestas:
C, (14 + 15) = fuente de 29 bytes, ejecutable 17.179.875.837 (16 GB)
Gracias a @viraptor por 6 bytes de descuento.
Gracias a @hvd por 2 bytes de descuento y tamaño ejecutable x4.
Esto define la
main
función como una gran matriz e inicializa su primer elemento. Esto hace que GCC almacene toda la matriz en el ejecutable resultante.Debido a que esta matriz es más grande que 2GB, debemos proporcionar el
-mcmodel=medium
indicador a GCC. Los 15 bytes adicionales se incluyen en la puntuación, según las reglas.No esperes que este código haga algo bueno cuando se ejecute.
Compilar con:
Me llevó un tiempo probar las sugerencias de @ hvd y encontrar una máquina con suficiente jugo para manejarla. Finalmente encontré una máquina virtual RedHat 5.6 que no es de producción, con 10 GB de RAM, 12 GB de intercambio y / tmp configurados en una gran partición local. La versión de GCC es 4.1.2. Tiempo total de compilación de unos 27 minutos.
fuente
a
. Usted sólo puede usarmain[1<<30]={1};
1<<30
entonces7<<28
podría ser una opción.C #, aproximadamente 1 minuto para compilar, binario de salida de 28 MB:
Agregar más Y aumentará el tamaño exponencialmente.
Una explicación de Pharap según la solicitud de @Odomontois:
Esta respuesta es abusar de los parámetros de herencia y tipo para crear recursividad. Para comprender lo que está sucediendo, primero es más fácil simplificar el problema. Considere
class X<A> { class Y : X<Y> { Y y; } }
, que genera la clase genéricaX<A>
, que tiene una clase internaY
.X<A>.Y
heredaX<Y>
, por lo tanto,X<A>.Y
también tiene una clase internaY
, que es entoncesX<A>.Y.Y
. Esto también tiene una clase internaY
, y esa clase internaY
tiene una clase interna,Y
etc. Esto significa que puede usar la resolución de alcance (.
) hasta el infinito, y cada vez que la usa, el compilador tiene que deducir otro nivel de herencia y parametrización de tipo .Al agregar parámetros de tipo adicionales, el trabajo que el compilador tiene que hacer en cada etapa se incrementa aún más.
Considere los siguientes casos:
In
class X<A> { class Y : X<Y> { Y y;} }
type paramA
tiene un tipo deX<A>.Y
.En
class X<A> { class Y : X<Y> { Y.Y y;} }
tipo paramA
tiene un tipo deX<X<A>.Y>.Y
.En
class X<A> { class Y : X<Y> { Y.Y.Y y;} }
tipo paramA
tiene un tipo deX<X<X<A>.Y>.Y>.Y
.En
class X<A,B> { class Y : X<Y,Y> { Y y;} }
tipo paramA
esX<A,B>.Y
yB
esX<A,B>.Y
.En
class X<A> { class Y : X<Y> { Y.Y y;} }
tipo paramA
esX<X<A,B>.Y, X<A,B>.Y>.Y
yB
esX<X<A,B>.Y, X<A,B>.Y>.Y
.En
class X<A> { class Y : X<Y> { Y.Y.Y y;} }
tipo paramA
esX<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y
yB
esX<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y
.Siguiendo este patrón, uno sólo puede imaginar 1 el trabajo del compilador tendría que hacer para deducir lo
A
queE
son enY.Y.Y.Y.Y.Y.Y.Y.Y
la definiciónclass 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 Podrías resolverlo, pero necesitarías mucha paciencia, e intellisense no te ayudará aquí.
fuente
Y
s .Python 3, fuente de 13 bytes, 9.057.900.463 byte (8.5GiB) .pyc-file
Editar : Cambié el código a la versión anterior después de que me di cuenta de que las reglas dicen que el tamaño de salida más allá de 4GiB no importa, y el código para este es un poco más corto; El código anterior, y lo que es más importante, la explicación, se puede encontrar a continuación.
Python 3, fuente de 16 bytes, archivo .pyc de 32 TB (si tiene suficiente memoria, espacio en disco y paciencia)
Explicación: Python 3 hace un plegado constante, y obtienes grandes números rápidamente con exponenciación. Sin embargo, el formato utilizado por los archivos .pyc almacena la longitud de la representación entera usando 4 bytes, y en realidad el límite parece ser más similar
2**31
, por lo que usando solo la exponenciación para generar un gran número, el límite parece generar 2GB. archivo pyc de una fuente de 8 bytes. (19**8
es un poco tímido8*2**31
, por lo que1<<19**8
tiene una representación binaria de menos de 2 GB; la multiplicación por ocho es porque queremos bytes, no bits)Sin embargo, las tuplas también son inmutables y la multiplicación de una tupla también se dobla constantemente, por lo que podemos duplicar ese blob de 2GB tantas veces como queramos, hasta al menos
2**31
veces, probablemente. La4**7
opción para llegar a 32 TB se eligió solo porque fue el primer exponente que pude encontrar que superó la respuesta anterior de 16 TB.Desafortunadamente, con la memoria que tengo en mi propia computadora, pude probar esto solo hasta un multiplicador de 2, es decir.
(1<<19**8,)*2
, que generó un archivo de 8,5 GB, que espero demuestre que la respuesta es realista (es decir, el tamaño del archivo no se limita a 2 ** 32 = 4 GB).Además, no tengo idea de por qué el tamaño del archivo que obtuve cuando probé fue de 8,5 GB en lugar de los 4 GB que esperaba, y el archivo es lo suficientemente grande como para no tener ganas de hurgarlo en este momento.
fuente
(1<<19**8,)*2
? 4 GB es suficiente.1<<18
en mi máquina (1.5GB) pero lo probaré en Linux más tarde, donde espero que funcione con los 8GB completos (¡no voy a probar la versión de 32TB!)python -m py_compile asd.py
generar el archivo .pyc."Template Haskell" permite que el código de Haskell se genere en tiempo de compilación usando Haskell, y por lo tanto es un preprocesador completo.
Aquí está mi intento, parametrizado por una expresión numérica arbitraria
FOO
:La magia es el código dentro del "empalme"
$(...)
. Esto se ejecutará en tiempo de compilación, para generar un AST de Haskell, que se injerta en el AST del programa en lugar del empalme.En este caso, hacemos un AST simple que representa el literal
0
, lo repetimosFOO
para hacer una lista, luego usamosListE
desde elLanguage.Haskell.TH
módulo para convertir esta lista de AST en un gran AST, que representa el literal[0, 0, 0, 0, 0, ...]
.El programa resultante es equivalente a
main = print [0, 0, 0, ...]
conFOO
repeticiones de0
.Para compilar a ELF:
Esto pesa 83 bytes (66 para el código Haskell y 17 para el
-XTemplateHaskell
argumento), más la longitud deFOO
.Podemos evitar el argumento del compilador y simplemente compilar con él
ghc
, pero tenemos que ponerlo{-# LANGUAGE TemplateHaskell#-}
al principio, lo que aumenta el código hasta 97 bytes.Aquí hay algunas expresiones de ejemplo para
FOO
, y el tamaño del binario resultante:Me quedé sin RAM compilando con
(2^20)
.También podemos hacer una lista infinita, usando en
repeat
lugar dereplicate FOO
, pero eso evita que el compilador se detenga;)fuente
[...].replicate (2^10)<$>[|0|])
). No tengo experiencia con Haskell; ¿Alguna pista sobre cómo hacer esta compilación?<$>
función se usa ampliamente en Haskell, pero solo se movió al "preludio" (el conjunto de funciones disponibles de forma predeterminada) en GHC 7.10. Para versiones anteriores, deberá agregarimport Control.Applicative;
después de laimport
declaración existente. Acabo de probar con GHC 7.8.4 y funciona.C ++, 250 + 26 = 276 bytes
Esta es la función de Ackermann implementada en plantillas. No puedo compilar
h=a<4,2>::n;
en mi pequeña máquina (6GB), pero logréh=a<3,14>
un archivo de salida de 26M. Puede ajustar las constantes para alcanzar los límites de su plataforma; consulte el artículo de Wikipedia vinculado para obtener orientación.Requiere un
-g
indicador para GCC (porque son todos los símbolos de depuración los que realmente consumen cualquier espacio) y una profundidad de plantilla mayor que la predeterminada. Mi línea de compilación terminó comoInformación de la plataforma
fuente
A+B
en cada clase, ahora lo pienso ...ASM, 61 bytes (fuente de 29 bytes, 32 bytes para banderas), 4,294,975,320 bytes ejecutables
Compilar con
gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold
fuente
1<<30
es lo suficientemente bueno para C. Como se trata de ensamblador, el tamaño está en bytes.as
se las arregla para entregarld
, perold
falla con esto . Ni siquiera-mcmodel=medium
parece ayudar.gold
enlazador:gcc -fuse-ld=gold ...
compilaciones / enlaces ... ¡eek! Terminado en 1:29 (89 segundos) y tamaño de 1,073,748,000 bytes.gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold
. Cuenta final:,4,294,975,320 bytes
con 32 bytes adicionales agregados a la longitud del programa para-mcmodel=large -Wl,-fuse-ld=gold
. Vale la pena señalar que el encabezado es incorrecto; la fuente es de 29 bytes (sin las banderas adicionales agregadas).1<<33
, terminé con un8,589,942,616
byte ejecutable.Aquí está mi respuesta C de 2005. Produciría un binario de 16 TB si tuviera 16 TB de RAM (no la tiene).
fuente
Preprocesador C simple: entrada de 214 bytes, salida de 5 MB
Inspirado por mi preprocesador del mundo real, falla aquí .
Los experimentos muestran que cada nivel de
#define
s hará (como se esperaba) que la salida sea aproximadamente diez veces mayor. Pero como este ejemplo tardó más de una hora en compilarse, nunca pasé a "G".fuente
Java, 450 + 22 = fuente de 472 bytes, archivo de clase ~ 1GB
B.java (versión de golf, advertencia durante la compilación)
B.java (versión sin golf)
Compilacion
Explicación
Esta bomba utiliza procesadores de anotación. Necesita 2 pases de compilación. El primer paso construye la clase de procesador
B
. Durante la segunda pasada, el procesador crea un nuevo archivo fuenteC.java
y lo compila aC.class
un tamaño de1,073,141,162
bytes.Existen varias limitaciones al intentar crear un archivo de clase grande:
error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool
.error: too many constants
.class
archivo. Si aumento16380
a16390
en el código anterior el compilador nunca regresa..java
archivo. El aumento16380
de16400
en el código anterior da como resultado:An exception has occurred in the compiler (1.8.0_66). Please file a bug ...
seguido de ajava.lang.IllegalArgumentException
.fuente
try..finally
(el código en el bloque finalmente se duplica para casos normales y excepcionales) y el bloque inicializador (el código del bloque inicializador se agrega a cada constructor)ä
por uni
y ajusté los números. Ahora la bomba debería crear una clase de 1GB en cualquier sistema sin problemas de codificación. Sin embargo, ahora necesita mucha más memoria.C, fuente de 26 bytes, salida de 2,139,103,367 bytes, programa válido
Compilado usando:
gcc cbomb.c -o cbomb
(gcc versión 4.6.3, Ubuntu 12.04, ~ 77 segundos)Pensé que trataría de ver qué tan grande podría hacer un programa válido sin usar ninguna opción de línea de comando. Tengo la idea de esta respuesta: https://codegolf.stackexchange.com/a/69193/44946 de Digital Trauma. Vea los comentarios allí sobre por qué esto se compila.
Cómo funciona:
const
elimina el indicador de escritura de las páginas del segmento, por lo que se puede ejecutar main. El195
es el código de máquina de Intel para una devolución. Y como la arquitectura Intel es little endian, este es el primer byte. El programa saldrá con el código de inicio que se haya puesto en el registro eax, probablemente 0.Solo se trata de 2 conciertos porque el enlazador está utilizando valores firmados de 32 bits para las compensaciones. Es 8 meg más pequeño que 2 conciertos porque el compilador / enlazador necesita algo de espacio para trabajar y este es el más grande que podría obtener sin errores del enlazador - ymmv.
fuente
Boo , 71 bytes. Tiempo de compilación: 9 minutos. 134,222,236 byte ejecutable
Utiliza una macro
R
(para Repetir) para hacer que el compilador multiplique la declaración de incremento un número arbitrario de veces. No se necesitan indicadores especiales del compilador; simplemente guarde el archivo comobomb.boo
e invoque el compiladorbooc bomb.boo
para compilarlo.fuente
2**e
-¿Que es esto? Trate9**e
!Kotlin , fuente de 90 bytes, binario JVM compilado de 177416 bytes (173 KB)
Técnicamente, podría hacer esto aún más largo al anidar aún más la expresión. Sin embargo, el compilador se bloquea con un
StackOverflow
error si aumenta la recursividad.fuente
C ++, 214 bytes (no se necesitan opciones especiales de compilación)
Es una recursión de plantilla bidimensional bastante sencilla (la profundidad de recursión es la raíz cuadrada del total de plantillas emitidas, por lo que no excederá los límites de la plataforma), con una pequeña cantidad de datos estáticos en cada una.
El archivo de objeto generado con
g++ 4.9.3 x86_64-pc-cygwin
es 2567355421 bytes (2.4GiB).El aumento del valor inicial por encima de 80 rompe el ensamblador cygwin gcc (demasiados segmentos).
Además,
99999
puede ser reemplazado9<<19
o similar para aumentar el tamaño sin cambiar el código fuente ... pero no creo que necesite usar más espacio en disco del que ya tengo;)fuente
-c
indicador de compilación para detener el enlazador (2 bytes adicionales), y no estoy seguro de poder aceptar la salida .o (no uno de los que enumeré). Aún así, me gusta, así que +1.Scala: fuente de 70 bytes, resultado de 22980842 bytes (después de jar)
Esto produce 9 5 (aproximadamente 59,000) archivos de clase especializados, que se empaquetan en un frasco de aproximadamente 23 MB. En principio, puede continuar si tiene un sistema de archivos que pueda manejar tantos archivos y suficiente memoria.
(Si se debe incluir el comando jar, son 82 bytes).
fuente
error: java.lang.OutOfMemoryError: GC overhead limit exceeded
. ¿Podría también documentar el comando requerido para la compilación?scalac -J-Xmx12G X.scala
es lo que usé. No probé cuánto necesita realmente.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
¿Puede especificar la versión de scala y java (quizás también la plataforma)? Usé scalac 2.9.2 y OpenJDK 1.8.0_66-internal-b17, en 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
C, 284 bytes + 2 para la
-c
engcc bomb.c -o bomb.o -c
; salida: 2 147 484 052 bytesfuente
Boo, mucho más de lo que puedes esperar de esto
fuente
Python 3:
Bomba de tetración
fuente