Construye una bomba compiladora

372

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 -lmcontará 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_ces 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) .

Dave
fuente
Si usa un transpilador, ¿el código fuente de salida debe tener menos de 512 bytes, así como el código fuente de entrada?
trichoplax
3
¿Se permite la transpilación repetida?
orlp
3
@ LegionMammal978 sí, tiene que producir uno de los tipos de archivo que especifiqué. Pero si crees que has encontrado algo que es más una máquina virtual que un lenguaje interpretado, pregúntale específicamente y es posible que lo permita (es un poco subjetivo, así que quería ser muy restrictivo para comenzar, con la opción de abrirlo)
Dave
3
@trichoplax No estaba al tanto de eso, pero según algunas lecturas parece que sí; compilar a Python bytecode cuenta absolutamente. Entonces, para python, el tamaño de salida sería el tamaño total de todos sus archivos pyc / pyo. Actualizaré la pregunta pronto con estas actualizaciones basadas en comentarios.
Dave
2
@MartinRosenau - WGroleau ya hizo una pregunta similar; Es estándar en los desafíos de codificación que puede usar cualquier cosa que ya existía cuando comenzó el desafío.
Dave

Respuestas:

441

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 mainfunció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=mediumindicador a GCC. Los 15 bytes adicionales se incluyen en la puntuación, según las reglas.

main[-1u]={1};

No esperes que este código haga algo bueno cuando se ejecute.

Compilar con:

gcc -mcmodel=medium cbomb.c -o cbomb

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.

Debido a la carga de CPU y RAM, recomiendo no realizar esta compilación en ninguna máquina remota relacionada con la producción .

Trauma digital
fuente
13
Estoy jugando contra mi solución aquí, pero ... no necesitas a. Usted sólo puede usarmain[1<<30]={1};
viraptor
38
Oh mi. Esto es malo X se congeló durante varios minutos tratando de compilar ese código. Estaba empezando a buscar otra computadora para posiblemente volver a ingresar y matar el proceso gcc antes de que finalmente volviera a la vida. Por cierto. Si desea un valor mayor que 1<<30entonces 7<<28podría ser una opción.
kasperd
33
> 4 gb? Eso se intensificó rápidamente
Wayne Werner el
18
En caso de que alguien más se pregunte por qué esto se compila: stackoverflow.com/questions/34764796/…
TC
206

C #, aproximadamente 1 minuto para compilar, binario de salida de 28 MB:

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;}}

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érica X<A>, que tiene una clase interna Y. X<A>.Yhereda X<Y>, por lo tanto, X<A>.Ytambién tiene una clase interna Y, que es entonces X<A>.Y.Y. Esto también tiene una clase interna Y, y esa clase interna Ytiene una clase interna, Yetc. 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 param Atiene un tipo de X<A>.Y.
En class X<A> { class Y : X<Y> { Y.Y y;} }tipo param Atiene un tipo de X<X<A>.Y>.Y.
En class X<A> { class Y : X<Y> { Y.Y.Y y;} }tipo param Atiene un tipo de X<X<X<A>.Y>.Y>.Y.
En class X<A,B> { class Y : X<Y,Y> { Y y;} }tipo param Aes X<A,B>.Yy Bes X<A,B>.Y.
En class X<A> { class Y : X<Y> { Y.Y y;} }tipo param Aes X<X<A,B>.Y, X<A,B>.Y>.Yy Bes X<X<A,B>.Y, X<A,B>.Y>.Y.
En class X<A> { class Y : X<Y> { Y.Y.Y y;} }tipo param Aes X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Yy Bes X<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 Aque Eson en Y.Y.Y.Y.Y.Y.Y.Y.Yla definición 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 Podrías resolverlo, pero necesitarías mucha paciencia, e intellisense no te ayudará aquí.

Vladimir Reshetnikov
fuente
14
¡Esto es más como el tipo de locura que esperaba! Parece que me voy a reinstalar Mono ...
Dave
31
¿Puedes dar una explicación de tan notorio efecto?
Odomontois
16
+1 por hacer más que solo inicializar una gran matriz.
Stig Hemmer
66
Aquí hay un ejemplo usando Try Roslyn y solo 3 Ys .
Kobi
10
Vi esta pregunta e inmediatamente pensé en ti. ¡Agradable!
Eric Lippert
154

Python 3, fuente de 13 bytes, 9.057.900.463 byte (8.5GiB) .pyc-file

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

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)

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

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**8es un poco tímido 8*2**31, por lo que 1<<19**8tiene 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**31veces, probablemente. La 4**7opció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.

Aleksi Torhamo
fuente
2
+1, pero ¿por qué no (1<<19**8,)*2? 4 GB es suficiente.
Akangka
2
@ChristianIrwan: Sí, olvidé esa regla, solo me di cuenta hace unos minutos y aún no he descubierto qué tipo de edición debo hacer. :-)
Aleksi Torhamo
1
Agradable. Como esto es solo 13 bytes, ¡finalmente tenemos un desafío a la primera respuesta publicada! Solo pude confirmar 1<<18en 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!)
Dave
1
@Dave: el tamaño exacto puede depender de la versión (1.5GB suena raro sin importar qué) Estaba usando Python 3.3.5, y solía python -m py_compile asd.pygenerar el archivo .pyc.
Aleksi Torhamo
3
IIRC, python utiliza 30 bits por palabra de 32 bits en su representación entera
130

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) .

"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:

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

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 repetimos FOOpara hacer una lista, luego usamos ListEdesde el Language.Haskell.THmó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, ...]con FOOrepeticiones de 0.

Para compilar a 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

Esto pesa 83 bytes (66 para el código Haskell y 17 para el -XTemplateHaskellargumento), más la longitud de FOO.

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:

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

Me quedé sin RAM compilando con (2^20).

También podemos hacer una lista infinita, usando en repeatlugar de replicate FOO, pero eso evita que el compilador se detenga;)

Warbo
fuente
46
Bienvenido a Programming Puzzles y Code Golf. Esta es una respuesta brillante , especialmente para un nuevo usuario de este sitio. Si necesita ayuda (que dudo), no dude en preguntar.
wizzwizz4
3
@ wizzwizz4: Sí, es una respuesta brillante. Es esencialmente lo mismo que el mío, excepto que en Haskell requiere una directiva especial de compilación para que la metaprogramación funcione. ;)
Mason Wheeler
2
Cuando compilo con GHC 7.8.3 obtengo "No está en el alcance: '<$>'" (configuro el código en [...].replicate (2^10)<$>[|0|])). No tengo experiencia con Haskell; ¿Alguna pista sobre cómo hacer esta compilación?
Dave
38
Lástima que la plantilla haskell no sea lo suficientemente perezosa como para transmitir un ejecutable infinito.
PyRulez
1
Hola @Dave, la <$>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á agregar import Control.Applicative;después de la importdeclaración existente. Acabo de probar con GHC 7.8.4 y funciona.
Warbo
80

C ++, 250 + 26 = 276 bytes

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;

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 -gindicador 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ó como

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

Información de la plataforma

g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Linux 3.13.0-46-generic #79-Ubuntu SMP x86_64 GNU/Linux
Toby Speight
fuente
Realmente me gusta este, pero no estoy seguro de poder aceptar una salida .o, ya que dije ELF / .exe / etc. (¡y compilar esto lo optimiza completamente!). Aún así, +1 (y confirmado)
Dave
44
Actualización: Como Ben Voigt señala en su respuesta, GCC en Linux no generar archivos ELF como .o de salida, y he sido capaz de confirmar la <3,14> variante con él, así yup - esto es válido.
Dave
17
Esperaba que saliera algo absurdo de las plantillas de C ++. Yo no estaba esperando la función de Ackermann.
Mark
¿Fibonacci no le dará un código más pequeño y un mejor control de tamaño de salida?
Will Ness
1
¡Pero queremos un código más grande! Fibonacci proporciona casi el mismo tamaño que el código lineal puro (pero un tiempo de compilación más largo que el lineal). Ciertamente podría divertirse con una matriz estática de tamaño A+Ben cada clase, ahora lo pienso ...
Toby Speight
65

ASM, 61 bytes (fuente de 29 bytes, 32 bytes para banderas), 4,294,975,320 bytes ejecutables

.globl main
main:
.zero 1<<32

Compilar con gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold

viraptor
fuente
55
1<<30es lo suficientemente bueno para C. Como se trata de ensamblador, el tamaño está en bytes.
viraptor
2
@viraptor Mi sistema tiene 32GB de RAM y por diversión intenté construir su código. asse las arregla para entregar ld, pero ldfalla con esto . Ni siquiera -mcmodel=mediumparece ayudar.
Iwillnotexist Idonotexist
2
intente forzar el uso del goldenlazador: gcc -fuse-ld=gold ...compilaciones / enlaces ... ¡eek! Terminado en 1:29 (89 segundos) y tamaño de 1,073,748,000 bytes.
lornix
2
Finalmente conseguí esto para ensamblar en Ubuntu 15.10 de 64 bits, con invocación gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold. Cuenta final:, 4,294,975,320 bytescon 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).
Mego
3
Al aumentar la asignación hasta 1<<33, terminé con un 8,589,942,616byte ejecutable.
Mego
60

Aquí está mi respuesta C de 2005. Produciría un binario de 16 TB si tuviera 16 TB de RAM (no la tiene).

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(){}
Joshua
fuente
19
"Produciría un binario de 16 TB si tuviera 16 TB de RAM (no la tiene)". - ¡tampoco tengo un disco duro de 16TB! Realmente no puedo verificar esto, pero de todos modos es genial.
Dave
55
Descubrí este por accidente y vi que el compilador se volcaba cuando se quedaba sin espacio de direcciones.
Joshua
8
NO intente jugar golf a esta entrada; el golf derrota la intención del ejemplo de código y de todos modos no hay beneficios de puntaje al hacerlo. El código ya tiene licencia GPL a partir de 2005.
Joshua
66
@BenVoigt Independientemente, editar el código de otras personas nunca es aceptable aquí. Deja un comentario si hay un problema. Meta publicación relevante: meta.codegolf.stackexchange.com/questions/1615/…
Mego
2
@ Joshua: Comprueba la diferencia de rebajas. Mego solo agregó la pista de resaltado.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
25

Preprocesador C simple: entrada de 214 bytes, salida de 5 MB

Inspirado por mi preprocesador del mundo real, falla aquí .

#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; }

Los experimentos muestran que cada nivel de #defines 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".

Thomas Padron-McCarthy
fuente
99
Esto es como una bomba xml
una tijereta el
99
Específicamente es una implementación del original "Billion Laughs".
mınxomaτ
Esto es una locura pero simple.
Vahid Amiri
2
Wow, esto realmente causa un defecto en GCC 4.9 y Clang. ¿Qué compilador usaste?
Dave
1
@Dave: Extraño. Cuando compilo usando make, se compila, pero si escribo exactamente el mismo comando que make usa, se bloquea. Y no parece estar relacionado con variables de entorno.
Thomas Padron-McCarthy
24

Java, 450 + 22 = fuente de 472 bytes, archivo de clase ~ 1GB

B.java (versión de golf, advertencia durante la compilación)

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 (versión sin golf)

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;
    }
}

Compilacion

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

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 fuente C.javay lo compila a C.classun tamaño de1,073,141,162 bytes.

Existen varias limitaciones al intentar crear un archivo de clase grande:

  • Crear identificadores de más de 64k resulta en: error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool .
  • Crear más de aproximadamente 64k variables / funciones resulta en: error: too many constants
  • También hay un límite de aproximadamente 64k para el tamaño del código de una función.
  • Parece que hay un límite general (¿error?) En el compilador de Java de aproximadamente 1 GB para el .classarchivo. Si aumento 16380a16390 en el código anterior el compilador nunca regresa.
  • También hay un límite de aproximadamente 1 GB para el .javaarchivo. El aumento 16380de 16400en el código anterior da como resultado: An exception has occurred in the compiler (1.8.0_66). Please file a bug ...seguido de a java.lang.IllegalArgumentException.
Sleafar
fuente
10
Ordenado; esencialmente ha creado su propio preprocesador, dentro del límite de tamaño, en un lenguaje con un compilador que admite de forma nativa preprocesadores personalizados. Está dentro de las reglas. La clase final fue de solo 0.5GB para mí, pero puedo confirmar el método.
Dave
Otro ejemplo en Java habrahabr.ru/post/245333 : utiliza anidado 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)
Victor
Reemplacé el äpor un iy 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.
Sleafar
? extiende TypeElement?!?
gato
22

C, fuente de 26 bytes, salida de 2,139,103,367 bytes, programa válido

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

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: constelimina el indicador de escritura de las páginas del segmento, por lo que se puede ejecutar main. El 195es 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.

Zakipu
fuente
3
Como comentario interesante, la salida es de 2.078.451 bytes con compresión máxima = relación de compresión 1029: 1.
Zakipu
20

Boo , 71 bytes. Tiempo de compilación: 9 minutos. 134,222,236 byte ejecutable

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

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 como bomb.booe invoque el compilador booc bomb.boopara compilarlo.

Mason Wheeler
fuente
2**e-¿Que es esto? Trate 9**e!
wchargin
1
@WChargin: ¡Lo divertido de la metaprogramación es lo fácil que puede personalizarla!
Mason Wheeler
Tengo algunos problemas para instalar boo ... ¡Confirmaré esto cuando logre instalarlo!
Dave
@Dave ¿Qué problemas tienes con eso?
Mason Wheeler
16

Kotlin , fuente de 90 bytes, binario JVM compilado de 177416 bytes (173 KB)

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)}}}}}}}}}}}

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 StackOverflowerror si aumenta la recursividad.

El numero uno
fuente
Sus prefijos SI no están de acuerdo. ¿Es eso 177416 kilobytes = 173 MB, o 177416 bytes = 173 kB?
Ben Voigt el
1
@BenVoigt Gracias por señalarlo: D
TheNumberOne
Impresionante, tiene un +1
J Atkin
Para que se compile Kotlin 1.2.20 necesitamos eliminar una profundidad y es ~ 104kB. ¿Qué versión usaste originalmente?
TWiStErRob
15

C ++, 214 bytes (no se necesitan opciones especiales de compilación)

#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();

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-cygwines 2567355421 bytes (2.4GiB).

El aumento del valor inicial por encima de 80 rompe el ensamblador cygwin gcc (demasiados segmentos).

Además, 99999puede ser reemplazado 9<<19o 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;)

Ben Voigt
fuente
Confirmado (de hecho, es 2.56GB con clang), pero necesita un -cindicador 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.
Dave
@Dave: los archivos gcc .o tienen formato ELF, ¿no?
Ben Voigt el
No es seguro. No comienzan con un número mágico ELF cuando los genero ... Investigaré más tarde.
Dave
@Dave: Bueno, cygwin gcc no está generando un archivo ELF. Linux gcc parece (aunque estoy viendo uno de un código diferente)
Ben Voigt
Sí, GCC 5.2.1 en Kubuntu está generando un archivo ELF, ¡pero solo tiene 9 MB! No estoy seguro de cómo se logró comprimirlo tanto en comparación con los otros compiladores. Tal vez GCC 4.9 haría un archivo ELF de 2GB.
Dave
6

Scala: fuente de 70 bytes, resultado de 22980842 bytes (después de jar)

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

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).

Rex Kerr
fuente
No podía compilarlo: error: java.lang.OutOfMemoryError: GC overhead limit exceeded. ¿Podría también documentar el comando requerido para la compilación?
P.Péter
@ P.Péter: debe darle más memoria al compilador, por ejemplo, scalac -J-Xmx12G X.scalaes lo que usé. No probé cuánto necesita realmente.
Rex Kerr
todavía no se compila, lamentablemente :( 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.
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 Kerr
2

C, 284 bytes + 2 para la -cen gcc bomb.c -o bomb.o -c; salida: 2 147 484 052 bytes

#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};
H2CO3
fuente
0

Boo, mucho más de lo que puedes esperar de esto

macro R(e as int):for i in range(9**e):yield R.Body
x = 0
R 99:++x
user75200
fuente
Esto se parece a la respuesta de Mason Wheeler con algunos pequeños cambios (??). ¿Llegó a la misma respuesta de forma independiente o hay algo importante en los valores que cambió (si es así, edite la respuesta para explicar por qué son importantes).
Dave
0

Python 3:

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

Bomba de tetración

Ryan Burgert
fuente
2
Debe indicar cuántos bytes tiene la salida, para ver cómo su entrada se compara con otras.
Sanchises
Bienvenido a PPCG! Parece que accidentalmente creaste dos cuentas y publicaste esta respuesta dos veces. He eliminado la otra respuesta. Como dijo Sanchises, este desafío se califica por el tamaño del programa compilado . Por lo tanto, debe incluir ese tamaño en su respuesta, ya que es el puntaje principal. También tenga en cuenta que el programa real no será muy grande, solo la expresión que está creando en la memoria, por lo que es posible que desee pensar en un enfoque diferente.
Martin Ender
1
@MartinEnder debido a cómo Python evalúa algunas expresiones en tiempo de compilación y almacena números con precisión arbitraria, esto (en teoría) tendrá un ejecutable bastante grande. Pero como señaló Aleksi Torhamo (que utilizó la misma técnica para parte de su respuesta), esto tiene un límite de alrededor de 2 GB, por lo que esperaría que este código tal como está escrito probablemente no se compile (aunque no lo he comprobado ) Si el OP puede hacer que se compile y publique el tamaño compilado (junto con el comando necesario para generarlo), entonces es válido. La similitud con la respuesta existente de Aleksi me parece una coincidencia.
Dave