Costruisci una bomba del compilatore


372

introduzione

Probabilmente hai familiarità con bombe zip , bombe XML , ecc. In parole povere, sono file (relativamente) piccoli che producono un output enorme quando interpretati da software ingenuo. La sfida qui è abusare di un compilatore allo stesso modo.

Sfida

Scrivi del codice sorgente che occupa 512 byte o meno e che si compila in un file che occupa lo spazio più possibile. Vince il file di output più grande!

Regole

OK, quindi ci sono alcuni importanti chiarimenti, definizioni e restrizioni;

  • L'output della compilation deve essere un file ELF , un eseguibile portatile di Windows (.exe) o un bytecode virtuale per JVM o CLR di .Net (è probabile che anche altri tipi di bytecode virtuale siano OK se richiesto). Aggiornamento: anche l'output .pyc / .pyo di Python conta .
  • Se la tua lingua preferita non può essere compilata direttamente in uno di quei formati, è consentita anche la transpilazione seguita dalla compilazione ( Aggiornamento: puoi traspilare più volte, purché non usi mai la stessa lingua più di una volta ).
  • Il codice sorgente può essere costituito da più file e persino file di risorse, ma la dimensione sommata di tutti questi file non deve superare i 512 byte.
  • Non è possibile utilizzare alcun input diverso dai file di origine e dalla libreria standard della lingua prescelta. Le librerie standard di collegamento statico sono OK quando sono supportate. In particolare, nessuna libreria di terze parti o librerie del sistema operativo.
  • Deve essere possibile invocare la compilation usando un comando o una serie di comandi. Se durante la compilazione sono richiesti flag specifici, questi contano ai fini del limite di byte (ad es. Se la riga di compilazione è gcc bomb.c -o bomb -O3 -lm, la -O3 -lmparte (7 byte) verrà conteggiata (notare che lo spazio iniziale iniziale non viene conteggiato).
  • I preprocessori sono consentiti solo se sono un'opzione di compilazione standard per la tua lingua.
  • L'ambiente dipende da te, ma nell'interesse di renderlo verificabile, ti preghiamo di attenersi alle versioni recenti (cioè disponibili) del compilatore e ai sistemi operativi (e ovviamente specificare quale stai usando).
  • Deve compilare senza errori (gli avvisi sono OK) e l'arresto anomalo del compilatore non conta nulla.
  • Ciò che il tuo programma fa effettivamente è irrilevante, anche se non può essere nulla di dannoso. Non deve nemmeno essere in grado di iniziare.

Esempio 1

Il programma C.

main(){return 1;}

Compilato con Apple LLVM version 7.0.2 (clang-700.1.81)su OS X 10.11 (64 bit):

clang bomb.c -o bomb -pg

Produce un file di 9228 byte. La dimensione totale della sorgente è 17 + 3 (per -pg) = 20 byte, che è facilmente entro il limite della dimensione.

Esempio 2

Il programma Brainfuck:

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

Traspilato con awib ac con:

./awib < bomb.bf > bomb.c

Quindi compilato con Apple LLVM version 7.0.2 (clang-700.1.81)su OS X 10.11 (64 bit):

clang bomb.c

Produce un file di 8464 byte. L'input totale qui è di 143 byte (poiché @lang_cè il valore predefinito per awib, non è stato necessario aggiungerlo al file sorgente e non ci sono flag speciali su entrambi i comandi).

Si noti inoltre che in questo caso, il file bomb.c temporaneo è di 802 byte, ma ciò non conta né per la dimensione di origine né per la dimensione di output.

Nota finale

Se si ottiene un output superiore a 4 GB (forse se qualcuno trova un preprocessore completo turing), la competizione sarà per la fonte più piccola che produce un file di almeno quella dimensione (non è pratico testare gli invii che diventano troppo grandi) .


Se si utilizza un transpiler, il codice sorgente di output deve essere inferiore a 512 byte e il codice sorgente di input?
trichoplax,

3
È consentita una ripetuta traspilazione?
Orlp,

3
@ LegionMammal978 sì, deve produrre uno dei tipi di file che ho specificato. Ma se pensi di aver trovato qualcosa che è più una macchina virtuale che un linguaggio interpretato, chiedilo in modo specifico ed è possibile che lo permetterò (è un po 'soggettivo, quindi volevo essere molto restrittivo per iniziare, con l'opzione di aprirlo)
Dave,

3
@trichoplax Non ne ero a conoscenza, ma da alcune letture sembra di sì; la compilazione in bytecode Python conta assolutamente. Quindi per Python, la dimensione dell'output sarebbe la somma della dimensione totale di tutti i tuoi file pyc / pyo. Presto aggiornerò la domanda con questi aggiornamenti basati su commenti.
Dave,

2
@MartinRosenau - WGroleau ha già posto una domanda simile; è standard nelle sfide di codifica che puoi usare tutto ciò che esisteva già all'inizio della sfida.
Dave,

Risposte:


441

C, (14 + 15) = 29 byte sorgente, 17.179.875.837 (16 GB) eseguibile byte

Grazie a @viraptor per 6 byte di sconto.

Grazie a @hvd per 2 byte di sconto e dimensione eseguibile x4.

Questo definisce la mainfunzione come un grande array e inizializza il suo primo elemento. Questo fa sì che GCC memorizzi l'intero array nell'eseguibile risultante.

Poiché questo array è più grande di 2 GB, dobbiamo fornire il -mcmodel=mediumflag a GCC. I 15 byte extra sono inclusi nel punteggio, come da regole.

main[-1u]={1};

Non aspettarti che questo codice faccia qualcosa di carino quando viene eseguito.

Compilare con:

gcc -mcmodel=medium cbomb.c -o cbomb

Mi ci è voluto un po 'di tempo per provare i suggerimenti di @ hvd e trovare una macchina con abbastanza succo per gestirlo. Alla fine ho trovato una vecchia VM RedHat 5.6 non di produzione con 10 GB di RAM, 12 GB di swap e / tmp impostato su una grande partizione locale. La versione GCC è 4.1.2. Tempo di compilazione totale circa 27 minuti.

A causa del carico della CPU e della RAM, sconsiglio di fare questa compilazione su qualsiasi macchina remota legata alla produzione .



13
Sto giocando contro la mia soluzione qui, ma ... non è necessario a. Puoi semplicemente usaremain[1<<30]={1};
viraptor il

38
Oh mio. Questo è male X si bloccò per diversi minuti nel tentativo di compilare quel codice. Stavo iniziando a cercare un altro computer in cui poter tornare indietro e uccidere il processo gcc prima che finalmente tornasse in vita. Btw. Se si desidera un valore maggiore di 1<<30allora 7<<28potrebbe essere un'opzione.
Kasperd,

33
> 4gb? Ciò si intensificò rapidamente
Wayne Werner il

18
Nel caso in cui qualcun altro si chieda perché questo compili: stackoverflow.com/questions/34764796/…
TC

206

C #, circa 1 minuto per la compilazione, binario di uscita da 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;}}

L'aggiunta di più Y aumenterà le dimensioni in modo esponenziale.

Una spiegazione di Pharap secondo la richiesta di @Odomontois:

Questa risposta abusa dell'ereditarietà e digita i parametri per creare la ricorsione. Per capire cosa sta succedendo, è più semplice innanzitutto semplificare il problema. Considerare class X<A> { class Y : X<Y> { Y y; } }, che genera la classe generica X<A>, che ha una classe interna Y. X<A>.Yeredita X<Y>, quindi X<A>.Yha anche una classe interiore Y, che è allora X<A>.Y.Y. Questo quindi ha anche una classe interna Ye quella classe interna Yha una classe interna Yecc. Ciò significa che è possibile utilizzare la risoluzione dell'ambito ( .) all'infinito e ogni volta che la si utilizza, il compilatore deve dedurre un altro livello di ereditarietà e parametrizzazione del tipo .

Aggiungendo parametri di tipo aggiuntivi, il lavoro che il compilatore deve fare in ogni fase è ulteriormente aumentato.

Considera i seguenti casi:
Nel class X<A> { class Y : X<Y> { Y y;} }tipo param Aha un tipo di X<A>.Y.
Nel class X<A> { class Y : X<Y> { Y.Y y;} }tipo param Aha un tipo di X<X<A>.Y>.Y.
Nel class X<A> { class Y : X<Y> { Y.Y.Y y;} }tipo param Aha un tipo di X<X<X<A>.Y>.Y>.Y.
Nel class X<A,B> { class Y : X<Y,Y> { Y y;} }tipo param Aè X<A,B>.Yed Bè X<A,B>.Y.
Nel class X<A> { class Y : X<Y> { Y.Y y;} }tipo param Aè X<X<A,B>.Y, X<A,B>.Y>.Yed Bè X<X<A,B>.Y, X<A,B>.Y>.Y.
Nel class X<A> { class Y : X<Y> { Y.Y.Y y;} }tipo param Aè X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Yed Bè X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y.

A seguito di questo modello, si può solo immaginare 1 il lavoro del compilatore avrebbe dovuto fare per dedurre cosa Aper Esono Y.Y.Y.Y.Y.Y.Y.Y.Ynella definizione 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 Potresti capirlo, ma avresti bisogno di molta pazienza e l'intellisense non ti aiuterà qui.


14
Questo è più simile al tipo di follia che mi aspettavo! Sembra che io sia fuori per reinstallare Mono ...
Dave,

31
Potete fornire una spiegazione di tale noto effetto?
Odomontois,

16
+1 per fare di più che inizializzare un array di grandi dimensioni.
Stig Hemmer,

6
Ecco un esempio usando Try Roslyn e solo 3 Ysecondi .
Kobi,

10
Ho visto questa domanda e ho pensato subito a te. Bello!
Eric Lippert,

154

Python 3, sorgente a 13 byte, 9.057.900.463 byte (8.5GiB) .pyc-file

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

Modifica : ho cambiato il codice con la versione precedente dopo che ho capito che le regole dicono che le dimensioni dell'output oltre 4GiB non contano, e il codice per questo è sempre leggermente più breve; Il codice precedente - e, soprattutto, la spiegazione - è disponibile di seguito.


Python 3, sorgente a 16 byte, file .pyc> 32 TB (se si dispone di memoria, spazio su disco e pazienza sufficienti)

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

Spiegazione: Python 3 esegue una piegatura costante e si ottengono rapidamente grandi numeri con l'espansione. Il formato utilizzato dai file .pyc memorizza la lunghezza della rappresentazione intera usando 4 byte, e in realtà il limite sembra essere più simile 2**31, quindi usando solo l'esponente per generare un numero elevato, il limite sembra generare un 2GB. file pyc da una sorgente di 8 byte. ( 19**8è un po 'timido 8*2**31, quindi 1<<19**8ha una rappresentazione binaria poco meno di 2 GB; la moltiplicazione per otto è perché vogliamo byte, non bit)

Tuttavia, anche le tuple sono immutabili e moltiplicare una tupla è anche piegato in modo costante, quindi possiamo duplicare quel BLOB da 2 GB tutte le volte che vogliamo, almeno fino a 2**31volte, probabilmente. Il 4**7per arrivare a 32 TB è stato scelto solo perché era il primo esponente che ho trovato che ha battuto la precedente risposta da 16 TB.

Sfortunatamente, con la memoria che ho sul mio computer, ho potuto testarlo solo fino a un moltiplicatore di 2, cioè. (1<<19**8,)*2, che ha generato un file da 8,5 GB, che spero dimostri che la risposta è realistica (cioè la dimensione del file non è limitata a 2 ** 32 = 4 GB).

Inoltre, non ho idea del motivo per cui la dimensione del file che ho ottenuto quando il test era di 8,5 GB invece dei 4 GB previsti, e il file è abbastanza grande da non aver voglia di cercarlo al momento.


2
+1, ma perché no (1<<19**8,)*2? 4 GB sono sufficienti.
Akangka,

2
@ChristianIrwan: Sì, avevo dimenticato quella regola, me ne sono reso conto solo pochi minuti fa e non ho ancora capito che tipo di modifica dovrei ancora fare. :-)
Aleksi Torhamo

1
Bello. Dal momento che sono solo 13 byte, finalmente abbiamo uno sfidante alla risposta pubblicata per prima! Sono stato in grado di confermare solo 1<<18sulla mia macchina (1,5 GB) ma lo testerò su Linux più tardi, dove mi aspetto che funzionerà con gli 8 GB completi (non proverò la versione da 32 TB!)
Dave,

1
@Dave: la dimensione esatta potrebbe dipendere dalla versione (1,5 GB suona strano, comunque); Stavo usando Python 3.3.5 e python -m py_compile asd.pygeneravo il file .pyc.
Aleksi Torhamo,

3
IIRC, python utilizza 30 bit per parola a 32 bit nella sua rappresentazione intera

130

Se si ottiene un output superiore a 4 GB (forse se qualcuno trova un preprocessore completo turing), la competizione sarà per la fonte più piccola che produce un file di almeno quella dimensione (non è pratico testare gli invii che diventano troppo grandi) .

"Template Haskell" consente di generare il codice Haskell in fase di compilazione utilizzando Haskell, ed è quindi un pre-processore completo turing.

Ecco il mio tentativo, parametrizzato da un'espressione numerica arbitraria FOO:

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

La magia è il codice all'interno della "giunzione" $(...). Questo verrà eseguito in fase di compilazione, per generare un AST di Haskell, che viene innestato sull'AST del programma al posto della giunzione.

In questo caso, creiamo un semplice AST che rappresenta il valore letterale 0, repliciamo questa FOOvolta per creare un elenco, quindi usiamo ListEdal Language.Haskell.THmodulo per trasformare questo elenco di AST in un unico grande AST, che rappresenta il valore letterale [0, 0, 0, 0, 0, ...].

Il programma risultante è equivalente a main = print [0, 0, 0, ...]con FOOripetizioni di 0.

Per compilare in 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

Questo pesa 83 byte (66 per il codice Haskell e 17 per l' -XTemplateHaskellargomento), più la lunghezza di FOO.

Possiamo evitare l'argomento del compilatore e compilarlo ghc, ma dobbiamo metterlo {-# LANGUAGE TemplateHaskell#-}all'inizio, che porta il codice a 97 byte.

Ecco alcune espressioni di esempio per FOOe la dimensione del file binario risultante:

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

Ho esaurito la compilazione della RAM con (2^20).

Possiamo anche creare un elenco infinito, usando al repeatposto di replicate FOO, ma ciò impedisce al compilatore di arrestarsi;)


46
Benvenuti in Programming Puzzle and Code Golf. Questa è una risposta brillante , soprattutto per un nuovo utente di questo sito. Se hai bisogno di aiuto (di cui dubito), non esitare a chiedere.
wizzwizz4,

3
@ wizzwizz4: Sì, è una risposta brillante. È essenzialmente uguale al mio, tranne per il fatto che in Haskell è necessaria una direttiva del compilatore speciale per far funzionare la metaprogrammazione. ;)
Mason Wheeler,

2
Quando compilo con GHC 7.8.3 ottengo "Not in scope: '<$>'" (ho impostato il codice su [...].replicate (2^10)<$>[|0|])). Non ho esperienza con Haskell; qualche suggerimento su come effettuare questa compilazione?
Dave,

38
Haskell modello troppo cattivo non è abbastanza pigro da riprodurre in streaming un eseguibile infinito.
PyRulez,

1
Ciao @Dave, la <$>funzione è ampiamente usata in Haskell, ma è stata spostata nel "preludio" (l'insieme di funzioni disponibili per impostazione predefinita) in GHC 7.10. Per le versioni precedenti dovrai aggiungere import Control.Applicative;dopo l' importistruzione esistente . Ho appena provato con GHC 7.8.4 e funziona.
Warbo,

80

C ++, 250 + 26 = 276 byte

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;

Questa è la funzione Ackermann implementata nei template. Non riesco a compilare con la h=a<4,2>::n;mia piccola macchina (6 GB), ma sono riuscito a gestire h=a<3,14>un file di output di 26M. È possibile ottimizzare le costanti per raggiungere i limiti della propria piattaforma - consultare l'articolo di Wikipedia collegato per assistenza.

Richiede -gflag su GCC (perché sono tutti i simboli di debug che effettivamente consumano qualsiasi spazio) e una profondità del modello maggiore del valore predefinito. La mia riga di compilazione è finita come

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

Informazioni sulla piattaforma

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

Mi piace davvero questo, ma non sono sicuro di poter accettare un output .o, dal momento che ho detto ELF / .exe / etc. (e la compilazione completa lo ottimizza completamente!). Ancora, +1 (e confermato)
Dave,

4
Aggiornamento: Come Ben Voigt sottolinea la sua risposta, GCC su Linux non genera file ELF come .o uscita, e sono stato in grado di confermare la <3,14> variante con esso, in modo Yup - questo è valido.
Dave,

17
Mi aspettavo qualcosa di assurdo da modelli C ++. Non mi aspettavo la funzione Ackermann.
Mark

Fibonacci non ti darà un codice più piccolo e un migliore controllo della dimensione dell'output?
Will Ness,

1
Ma vogliamo un codice più grande! Fibonacci fornisce quasi le stesse dimensioni del codice lineare puro (ma un tempo di compilazione più lungo di quello lineare). Potresti sicuramente divertirti con una serie statica di dimensioni A+Bin ogni classe, ora ci penso ...
Toby Speight,

65

ASM, 61 byte (29 byte di origine, 32 byte per flag), 4.294.975.320 byte eseguibili

.globl main
main:
.zero 1<<32

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


5
1<<30è abbastanza buono per C. Dato che questo è assemblatore, la dimensione è in byte.
viraptor,

2
@viraptor Il mio sistema ha 32 GB di RAM e per i calci ho provato a costruire il tuo codice. asriesce a passare ld, ma ldfallisce con questo . Nemmeno -mcmodel=mediumsembra aiutare.
Iwillnotexist Idonotexist,

2
prova a forzare l'uso del goldlinker: gcc -fuse-ld=gold ...compila / link ... eek! Terminato in 1:29 (89 secondi) e dimensioni di 1.073.748.000 byte.
lornix,

2
Ho finalmente ottenuto questo da assemblare su Ubuntu 15.10 a 64 bit, con invocazione gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold. Conteggio finale:, 4,294,975,320 bytescon 32 byte extra aggiunti alla lunghezza del programma per -mcmodel=large -Wl,-fuse-ld=gold. Vale la pena notare che l'intestazione non è corretta; l'origine è di 29 byte (senza l'aggiunta di flag aggiuntivi).
Mego

3
Aumentando l'allocazione fino a 1<<33, ho finito con un 8,589,942,616eseguibile byte.
Mego

60

Ecco la mia risposta C del 2005. Produrrebbe un file binario da 16 TB se avessi RAM da 16 TB (non lo fai).

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
"Produrrebbe un binario da 16 TB se avessi 16 TB di RAM (non lo fai)." - non ho nemmeno un disco rigido da 16 TB! Non riesco davvero a verificarlo, ma è comunque bello.
Dave,

5
L'ho scoperto per caso e ho visto il compilatore cadere quando ha esaurito lo spazio degli indirizzi.
Joshua,

8
Si prega di NON tentare di giocare a golf questa voce; il golf sconfigge l'intento dell'esempio di codice e non ci sono comunque vantaggi in termini di punteggio. Il codice è già GPL dal 2005.
Joshua

6
@BenVoigt Indipendentemente da ciò, la modifica del codice di altre persone non è mai accettabile qui. Lascia un commento se c'è un problema. Meta post pertinente: meta.codegolf.stackexchange.com/questions/1615/…
Mego

2
@Joshua: controlla la differenza markdown. Mego ha aggiunto solo il suggerimento di evidenziazione.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

25

Preprocessore C semplice vecchio: 214 byte in ingresso, 5 MB in uscita

Ispirato dal mio preprocessore del mondo reale non riesco qui .

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

Gli esperimenti mostrano che ogni livello di #defines (come previsto) renderà l'output circa dieci volte più grande. Ma poiché questo esempio ha richiesto più di un'ora per essere compilato, non sono mai passato a "G".


9
Questo è un po 'come una bomba xml
un earwig

9
Nello specifico si tratta di un'implementazione dell'originale "Miliardi di risate".
mınxomaτ,

Questo è folle ma semplice.
Vahid Amiri,

2
Wow, questo in realtà provoca un segfault in GCC 4.9 e Clang. Quale compilatore hai usato?
Dave,

1
@Dave: strano. Quando compilo usando make, si compila, ma se scrivo esattamente lo stesso comando che make utilizza, si arresta in modo anomalo. E non sembra essere correlato alle variabili di ambiente.
Thomas Padron-McCarthy,

24

Java, 450 + 22 = 472 byte sorgente, file di classe ~ 1GB

B.java (versione golfizzata, avviso durante la compilazione)

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 (versione non golfizzata)

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

Compilazione

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

Spiegazione

Questa bomba utilizza processori di annotazione. Ha bisogno di 2 passaggi di compilazione. Il primo passaggio crea la classe del processore B. Durante il secondo passaggio, il processore crea un nuovo file di origine C.javae lo compila in un C.classcon una dimensione di 1,073,141,162byte.

Esistono diverse limitazioni quando si tenta di creare un file di grande classe:

  • La creazione di identificatori più lungo di circa 64k risultati in: error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool.
  • La creazione di oltre 64k variabili / funzioni comporta: error: too many constants
  • C'è anche un limite di circa 64k per la dimensione del codice di una funzione.
  • Sembra esserci un limite generale (bug?) Nel compilatore java di circa 1 GB per il .classfile. Se io aumentare 16380a 16390nel codice qui sopra il compilatore non ritorna mai.
  • C'è anche un limite di circa 1 GB per il .javafile. Aumentando 16380a 16400nel codice precedente si ottiene: An exception has occurred in the compiler (1.8.0_66). Please file a bug ...seguito da a java.lang.IllegalArgumentException.

10
Neat; hai essenzialmente creato il tuo preprocessore, entro il limite di dimensioni, in una lingua con un compilatore che supporta nativamente i preprocessori personalizzati. È all'interno delle regole. La classe finale era solo 0,5 GB per me, ma posso confermare il metodo.
Dave,

Un altro esempio in Java habrahabr.ru/post/245333 - utilizza nidificato try..finally(il codice nel blocco finally viene duplicato per casi normali ed eccezionali) e il blocco di inizializzatore (il codice dal blocco di inizializzatore viene aggiunto a ciascun costruttore)
Victor

Ho sostituito il äda un ie ho modificato i numeri. Ora la bomba dovrebbe creare una classe da 1 GB su qualsiasi sistema senza problemi di codifica. Tuttavia, ora richiede molta più memoria.
Sleafar,

? estende TypeElement?!?
gatto


22

C, sorgente 26 byte, uscita 2.139.103.367 byte, programma valido

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

Compilato usando: gcc cbomb.c -o cbomb(versione gcc 4.6.3, Ubuntu 12.04, ~ 77 secondi)

Ho pensato di provare a vedere quanto potevo fare un programma valido senza usare alcuna opzione da riga di comando. Ho avuto l'idea da questa risposta: https://codegolf.stackexchange.com/a/69193/44946 di Digital Trauma. Vedi i commenti lì sul perché questo compila.

Come funziona: constrimuove il flag di scrittura dalle pagine del segmento, quindi main può essere eseguito. Il 195è il codice macchina Intel per un ritorno. E poiché l'architettura Intel è little-endian, questo è il primo byte. Il programma uscirà con qualunque codice di avvio inserito nel registro eax, probabilmente 0.

È solo circa 2 gig perché il linker utilizza valori con segno a 32 bit per gli offset. È 8 mega più piccolo di 2 gig perché il compilatore / linker ha bisogno di spazio per funzionare e questo è il più grande che potrei ottenere senza errori di linker - ymmv.


3
A parte ciò, l'output è di 2.078.451 byte compressi con compressione massima = rapporto di compressione 1029: 1.
Zakipu,

20

Boo , 71 byte. Tempo di compilazione: 9 minuti. 134.222.236 byte eseguibile

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

Utilizza una macro R(per Ripeti) per far sì che il compilatore moltiplichi l'istruzione di incremento un numero arbitrario di volte. Non sono necessari flag di compilazione speciali; è sufficiente salvare il file come bomb.booe invocare il compilatore booc bomb.booper crearlo.


2**e-cos'è questo? Prova 9**e!
mercoledì

1
@WChargin: La cosa divertente della metaprogrammazione è la facilità con cui puoi personalizzarla!
Mason Wheeler,

Sto riscontrando un po 'di problemi con l'installazione di boo ... Lo confermerò quando riesco a installarlo!
Dave,

@Dave Che problemi hai?
Mason Wheeler,

16

Kotlin , sorgente di 90 byte, 177416 byte (173 KB) compilato binario 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)}}}}}}}}}}}

Tecnicamente, potresti renderlo ancora più lungo annidando ulteriormente l'espressione. Tuttavia, il compilatore si arresta in modo anomalo con un StackOverflowerrore se si aumenta la ricorsione.


I tuoi prefissi SI non sono d'accordo. 177416 kilobyte = 173 MB o 177416 byte = 173 kB?
Ben Voigt,

1
@BenVoigt Grazie per averlo sottolineato: D
TheNumberOne

Impressionante, prendi un +1
J Atkin il

Per compilare Kotlin 1.2.20 dobbiamo rimuovere una profondità ed è ~ 104kB. Quale versione hai usato originariamente?
TWiStErRob il

15

C ++, 214 byte (non sono necessarie opzioni di compilazione speciali)

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

È una ricorsione del modello bidimensionale abbastanza semplice (la profondità di ricorsione va come la radice quadrata dei modelli totali emessi, quindi non supererà i limiti della piattaforma), con una piccola quantità di dati statici in ciascuno.

Il file oggetto generato con g++ 4.9.3 x86_64-pc-cygwinè 2567355421 byte (2.4GiB).

L'aumento del valore iniziale sopra 80 interrompe l'assemblatore gg cygwin (troppi segmenti).

Inoltre, 99999può essere sostituito 9<<19o simile per aumentare le dimensioni senza modificare il codice sorgente ... ma non credo di dover utilizzare più spazio su disco di quanto non sia già;)


Confermato (in effetti, è 2,56 GB con clang), ma ha bisogno di un -cflag di compilazione per arrestare il linker (2 byte extra) e non sono sicuro di poter accettare .o output (non uno di quelli che ho elencato). Comunque, mi piace, quindi +1.
Dave,

@Dave: i file gcc .o sono in formato ELF, vero?
Ben Voigt,

Non sono sicuro. Non iniziano con un numero magico ELF quando li genererò ... Analizzerò più tardi.
Dave,

@Dave: cygwin gcc non sta generando un file ELF. Linux gcc sembra (anche se ne sto guardando uno da un altro pezzo di codice)
Ben Voigt,

Sì, GCC 5.2.1 su Kubuntu sta effettivamente generando un file ELF, ma è solo 9 MB! Non sono sicuro di come sia riuscito a comprimerlo così tanto rispetto agli altri compilatori. Forse GCC 4.9 creerebbe un file ELF da 2 GB.
Dave,

6

Scala - Sorgente 70 byte, risultato 22980842 byte (dopo il vaso)

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

Questo produce 9 5 (circa 59.000) file di classe specializzati, che si comprimono in un barattolo di circa 23 MB. In linea di principio puoi continuare se hai un filesystem in grado di gestire tanti file e memoria sufficiente.

(Se il comando jar deve essere incluso, è di 82 byte.)


Non riuscivo a compilarlo: error: java.lang.OutOfMemoryError: GC overhead limit exceeded. Potresti anche documentare il comando richiesto per la compilazione?
P.Péter,

@ P.Péter - Devi dare più memoria al compilatore, ad esempio scalac -J-Xmx12G X.scalaè quello che ho usato. Non ho testato quanto effettivamente ha bisogno.
Rex Kerr,

purtroppo ancora non compilando, purtroppo :( 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 foundPuoi specificare la versione scala e java (forse anche la piattaforma)? Ho usato scalac 2.9.2 e OpenJDK 1.8.0_66-internal-b17, su 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 byte + 2 per -cin gcc bomb.c -o bomb.o -c; uscita: 2 147 484 052 byte

#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

Boo, molto più di quanto tu possa aspettarti da questo

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

Questa sembra la risposta di Mason Wheeler con alcune piccole modifiche (??). Hai raggiunto la stessa risposta in modo indipendente o c'è qualcosa di importante nei valori che hai modificato (in tal caso, modifica la risposta per spiegare perché sono importanti).
Dave,

0

Python 3:

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

Bomba di tetrazione


2
Dovresti indicare quanti byte è l'output, per vedere come la tua voce si confronta con gli altri.
Sanchises,

Benvenuti in PPCG! Sembra che tu abbia creato accidentalmente due account e pubblicato questa risposta due volte. Ho rimosso l'altra risposta. Come diceva Sanchises, questa sfida è segnata dalle dimensioni del programma compilato . Quindi dovresti includere quella dimensione nella tua risposta in quanto è il punteggio principale. Nota anche che il programma attuale non sarà molto grande, ma solo l'espressione che stai creando in memoria, quindi potresti voler pensare a un approccio diverso.
Martin Ender,

1
@MartinEnder a causa del modo in cui Python valuta alcune espressioni in fase di compilazione e memorizza i numeri con precisione arbitraria, ciò avrà (in teoria) un eseguibile piuttosto grande. Ma come notato da Aleksi Torhamo (che ha usato la stessa tecnica per parte della sua risposta), questo ha un limite da qualche parte intorno ai 2 GB, quindi mi aspetto che questo codice scritto probabilmente non verrà compilato (anche se non ho controllato ). Se l'OP riesce a farlo compilare e registra la dimensione compilata (insieme al comando necessario per generarlo), allora è valido. La somiglianza con la risposta esistente di Aleksi mi sembra una coincidenza.
Dave,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.