Baue eine Compiler-Bombe


372

Einführung

Sie kennen sich wahrscheinlich mit Zip-Bomben , XML-Bomben usw. aus. Einfach ausgedrückt handelt es sich um (relativ) kleine Dateien, die bei der Interpretation durch naive Software eine enorme Leistung erbringen. Die Herausforderung besteht darin, einen Compiler auf die gleiche Weise zu missbrauchen.

Herausforderung

Schreiben Sie einen Quellcode, der 512 Bytes oder weniger belegt und der in eine Datei kompiliert wird, die den größtmöglichen Platz einnimmt. Die größte Ausgabedatei gewinnt!

Regeln

OK, es gibt einige wichtige Klarstellungen, Definitionen und Einschränkungen.

  • Die Ausgabe der Kompilierung muss eine ELF- Datei, eine Windows Portable Executable (.exe) oder ein virtueller Bytecode für die JVM oder die CLR von .Net sein (andere Arten von virtuellem Bytecode sind wahrscheinlich ebenfalls in Ordnung, wenn Sie dazu aufgefordert werden). Update: Pythons .pyc / .pyo-Ausgabe zählt ebenfalls .
  • Wenn Ihre bevorzugte Sprache nicht direkt in eines dieser Formate kompiliert werden kann, ist auch die Transpilation gefolgt von der Kompilierung zulässig ( Update: Sie können mehrere Transpilierungen durchführen, sofern Sie nie dieselbe Sprache mehr als einmal verwenden ).
  • Ihr Quellcode kann aus mehreren Dateien und sogar aus Ressourcendateien bestehen, die Gesamtgröße aller dieser Dateien darf jedoch 512 Byte nicht überschreiten.
  • Sie können keine anderen Eingaben als Ihre Quelldatei (en) und die Standardbibliothek der Sprache Ihrer Wahl verwenden. Das statische Verknüpfen von Standardbibliotheken ist OK, wenn dies unterstützt wird. Insbesondere keine Bibliotheken von Drittanbietern oder Betriebssystembibliotheken.
  • Es muss möglich sein, Ihre Kompilierung mit einem Befehl oder einer Reihe von Befehlen aufzurufen. Wenn Sie bestimmte Flags erfordern beim Kompilieren, diese auf Ihre Byte - Grenze zählen (zB wenn Ihre Kompilierung Linie ist gcc bomb.c -o bomb -O3 -lm, das -O3 -lmwird ein Teil (7 Byte) gezählt werden (die anfängliche Spitzen Raum zu beachten , wird nicht mitgerechnet).
  • Präprozessoren sind nur zulässig , wenn sie eine Standard-Kompilierungsoption für Ihre Sprache sind.
  • Die Umgebung liegt bei Ihnen, aber um dies überprüfbar zu machen, halten Sie sich bitte an die neuesten (dh verfügbaren) Compilerversionen und Betriebssysteme (und geben Sie an, welche Sie verwenden).
  • Es muss fehlerfrei kompiliert werden (Warnungen sind in Ordnung) und ein Absturz des Compilers zählt für nichts.
  • Was Ihr Programm tatsächlich tut, ist irrelevant, obwohl es nichts Bösartiges sein kann. Es muss nicht einmal in der Lage sein zu starten.

Beispiel 1

Das C-Programm

main(){return 1;}

Kompiliert mit Apple LLVM version 7.0.2 (clang-700.1.81)OS X 10.11 (64-Bit):

clang bomb.c -o bomb -pg

Erzeugt eine Datei mit 9228 Bytes. Die Gesamtgröße der Quelle beträgt 17 + 3 (für die -pg) = 20 Bytes, was leicht innerhalb der Größenbeschränkung liegt.

Beispiel 2

Das Brainfuck-Programm:

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

Transpiled mit awib zu c mit:

./awib < bomb.bf > bomb.c

Dann kompiliert mit Apple LLVM version 7.0.2 (clang-700.1.81)OS X 10.11 (64-Bit):

clang bomb.c

Erzeugt eine Datei mit 8464 Bytes. Die Gesamteingabe beträgt hier 143 Byte (da @lang_cawib standardmäßig der Quelldatei hinzugefügt werden musste und in keinem der Befehle spezielle Flags vorhanden sind).

Beachten Sie auch, dass in diesem Fall die temporäre Datei bomb.c 802 Byte groß ist, dies jedoch weder für die Quell- noch für die Ausgabegröße gilt.

Schlussbemerkung

Wenn eine Ausgabe von mehr als 4 GB erreicht wird (wenn jemand einen hervorragenden vollständigen Präprozessor findet), wird der Wettbewerb um die kleinste Quelle ausgetragen, die eine Datei mit mindestens dieser Größe erstellt (es ist einfach nicht praktikabel, zu große Einreichungen zu testen ). .


Müssen bei Verwendung eines Transpilers der Ausgabe-Quellcode und der Eingabe-Quellcode unter 512 Byte liegen?
Trichoplax

3
Ist wiederholte Transpilation erlaubt?
Orlp

3
@ LegionMammal978 ja es muss einer der von mir angegebenen Dateitypen erzeugt werden. Wenn Sie jedoch der Meinung sind, dass Sie etwas gefunden haben, das eher eine virtuelle Maschine als eine interpretierte Sprache ist, fragen Sie nach, und es ist möglich, dass ich es zulasse der Eröffnung)
Dave

3
@trichoplax Mir war das nicht bewusst, aber nach einigem Lesen sieht es so aus, als ob ja; Das Kompilieren zu Python-Bytecode zählt absolut. Für Python entspricht die Ausgabegröße der Gesamtgröße aller Ihrer Pyc / Pyo-Dateien. Ich werde die Frage demnächst mit diesen kommentarbasierten Updates aktualisieren.
Dave

2
@MartinRosenau - WGroleau hat bereits eine ähnliche Frage gestellt; Beim Codieren von Herausforderungen ist es Standard, dass Sie alles verwenden können, was zu Beginn der Herausforderung bereits vorhanden war.
Dave

Antworten:


441

C, (14 + 15) = 29 Byte Quelle, 17.179.875.837 (16 GB) Byte ausführbar

Vielen Dank an @viraptor für 6 Bytes aus.

Dank an @hvd für 2 Bytes und die ausführbare Größe x4.

Dadurch wird die mainFunktion als großes Array definiert und das erste Element initialisiert. Dadurch speichert GCC das gesamte Array in der resultierenden ausführbaren Datei.

Da dieses Array größer als 2 GB ist, müssen wir das -mcmodel=mediumFlag für GCC bereitstellen . Die zusätzlichen 15 Bytes sind gemäß den Regeln in der Wertung enthalten.

main[-1u]={1};

Erwarten Sie nicht, dass dieser Code beim Ausführen etwas Nettes bewirkt.

Kompilieren mit:

gcc -mcmodel=medium cbomb.c -o cbomb

Ich habe eine Weile gebraucht, um den Vorschlag von @ hvd zu testen - und eine Maschine zu finden, die genug Saft enthält, um damit umzugehen. Schließlich fand ich eine alte Nicht-Produktions-RedHat 5.6-VM mit 10 GB RAM, 12 GB Swap und / tmp, die auf eine große lokale Partition eingestellt war. Die GCC-Version ist 4.1.2. Gesamte Kompilierzeit ca. 27 Minuten.

Aufgrund der CPU- und RAM-Auslastung empfehle ich, diese Kompilierung nicht auf einem produktionsbezogenen Remotecompiler durchzuführen .



13
Ich spiele hier gegen meine Lösung, aber ... das brauchst du nicht a. Sie können nur verwendenmain[1<<30]={1};
Viraptor

38
Oh mein. Das ist böse. X blieb einige Minuten stehen und versuchte, diesen Code zu kompilieren. Ich fing an, nach einem anderen Computer zu suchen, um möglicherweise den gcc-Prozess wieder einzuschalten und zu beenden, bevor er endlich wieder zum Leben erweckt wurde. Btw. Wenn Sie einen größeren Wert als 1<<30dann wollen, 7<<28könnte eine Option sein.
Kasperd

33
> 4 gb? Das eskalierte schnell
Wayne Werner

18
Für den Fall, dass sich jemand fragt, warum dies kompiliert: stackoverflow.com/questions/34764796/…
TC

206

C #, ca. 1 min zu kompilieren, 28MB Output Binary:

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

Das Hinzufügen von mehr Y erhöht die Größe exponentiell.

Eine Erklärung von Pharap gemäß der Anfrage von @Odomontois:

Diese Antwort missbraucht Vererbungs- und Typparameter, um eine Rekursion zu erstellen. Um zu verstehen, was passiert, ist es einfacher, das Problem zuerst zu vereinfachen. Betrachten Sie class X<A> { class Y : X<Y> { Y y; } }, was die generische Klasse erzeugt X<A>, die eine innere Klasse hat Y. X<A>.Yerbt X<Y>, hat also X<A>.Yauch eine innere Klasse Y, die dann ist X<A>.Y.Y. Dies hat dann auch eine innere Klasse Y, und diese innere Klasse Yhat eine innere Klasse Yusw. Dies bedeutet, dass Sie scope resolution ( .) ad infinitum verwenden können und jedes Mal, wenn Sie es verwenden, muss der Compiler eine andere Ebene der Vererbung und Typparametrisierung ableiten .

Durch Hinzufügen zusätzlicher Typparameter wird die Arbeit des Compilers in jeder Phase weiter erhöht.

Betrachten Sie die folgenden Fälle:
In class X<A> { class Y : X<Y> { Y y;} }type hat param Aeinen Typ von X<A>.Y.
In class X<A> { class Y : X<Y> { Y.Y y;} }type hat param Aeinen Typ von X<X<A>.Y>.Y.
In class X<A> { class Y : X<Y> { Y.Y.Y y;} }type hat param Aeinen Typ von X<X<X<A>.Y>.Y>.Y.
Im class X<A,B> { class Y : X<Y,Y> { Y y;} }Typ param Aist X<A,B>.Yund Bist X<A,B>.Y.
Im class X<A> { class Y : X<Y> { Y.Y y;} }Typ param Aist X<X<A,B>.Y, X<A,B>.Y>.Yund Bist X<X<A,B>.Y, X<A,B>.Y>.Y.
Im class X<A> { class Y : X<Y> { Y.Y.Y y;} }Typ param Aist X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Yund Bist X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y.

Nach diesem Muster kann man sich nur vorstellen 1 die Arbeit der Compiler würde tun müssen, um zu folgern , was sind in der Definition .AEY.Y.Y.Y.Y.Y.Y.Y.Yclass 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 Sie könnten es herausfinden, aber Sie würden viel Geduld benötigen, und Intellisense wird Ihnen hier nicht weiterhelfen.


14
Das ist eher die Art von Wahnsinn, die ich erwartet hatte! Es sieht so aus, als würde ich Mono neu installieren ...
Dave

31
Können Sie eine Erklärung für diesen berüchtigten Effekt abgeben?
Odomontois

16
+1 für mehr als nur das Initialisieren eines großen Arrays.
Stig Hemmer

6
Hier ist ein Beispiel mit Try Roslyn und nur 3 YSekunden .
Kobi

10
Ich habe diese Frage gesehen und sofort an dich gedacht. Nett!
Eric Lippert

154

Python 3, 13-Byte-Quelle, 9.057.900.463 Byte (8,5 GB) .pyc-Datei

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

Bearbeiten : Der Code wurde auf die obige Version geändert, nachdem mir klar wurde, dass die Regeln sagen, dass eine Ausgabegröße über 4 GB keine Rolle spielt und der Code für diese Version etwas kürzer ist. Der vorherige Code - und vor allem die Erklärung - finden Sie unten.


Python 3, 16-Byte-Quelle,> 32 TB .pyc-Datei (wenn Sie über genügend Arbeitsspeicher, Speicherplatz und Geduld verfügen)

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

Erklärung: Python 3 faltet konstant und Sie erhalten mit Exponentation schnell große Zahlen. Das Format, das von .pyc-Dateien verwendet wird, speichert die Länge der Ganzzahldarstellung mit 4 Bytes, und in Wirklichkeit scheint das Limit eher zu sein. Wenn Sie 2**31also nur Exponentation verwenden, um eine große Zahl zu generieren, scheint das Limit 2 GB zu generieren. pyc datei von einer 8 byte quelle. ( 19**8ist ein bisschen schüchtern 8*2**31, 1<<19**8hat also eine binäre Darstellung knapp 2 GB; die Multiplikation mit acht ist, weil wir Bytes wollen, keine Bits)

Tupel sind jedoch auch unveränderlich, und das Multiplizieren eines Tupels wird ebenfalls konstant gefaltet, sodass wir diesen 2-GB-Blob so oft duplizieren können, wie wir möchten 2**31, wahrscheinlich bis zu mindestens einem Mal. Der 4**7zu 32 TB zu bekommen, wurde nur gewählt, weil es der erste Exponent war, den ich finden konnte, der die vorherige 16 TB-Antwort schlug.

Leider konnte ich mit dem Speicher, den ich auf meinem eigenen Computer habe, dies nur bis zu einem Multiplikator von 2 testen, dh. (1<<19**8,)*2, die eine 8,5 GB-Datei erzeugt hat, was meiner Meinung nach zeigt, dass die Antwort realistisch ist (dh die Dateigröße ist nicht auf 2 ** 32 = 4 GB beschränkt).

Außerdem habe ich keine Ahnung, warum die Dateigröße beim Testen 8,5 GB statt der erwarteten 4 GB betrug, und die Datei ist groß genug, sodass ich im Moment keine Lust habe, darin herumzustöbern.


2
+1, aber warum nicht (1<<19**8,)*2? 4 GB sind genug.
Akangka

2
@ChristianIrwan: Ja, ich hatte diese Regel vergessen, sie erst vor ein paar Minuten erkannt und nicht herausgefunden, welche Art von Bearbeitung ich noch vornehmen sollte. :-)
Aleksi Torhamo

1
Nett. Da dies nur 13 Bytes sind, haben wir endlich einen Herausforderer für die zuerst gepostete Antwort! Ich konnte nur 1<<18auf meinem Computer (1,5 GB) bestätigen, aber ich werde es später unter Linux testen, wo ich erwarte, dass es mit den vollen 8 GB funktioniert (die 32-TB-Version wird nicht ausprobiert!)
Dave

1
@ Dave: Die genaue Größe kann von der Version abhängen (1,5 GB klingen jedoch komisch, egal was passiert); Ich habe Python 3.3.5 verwendet und python -m py_compile asd.pydamit die .pyc-Datei generiert.
Aleksi Torhamo

3
IIRC, Python verwendet 30 Bits pro 32-Bit-Wort in seiner Ganzzahldarstellung

130

Wenn eine Ausgabe von mehr als 4 GB erreicht wird (wenn jemand einen hervorragenden vollständigen Präprozessor findet), wird der Wettbewerb um die kleinste Quelle ausgetragen, die eine Datei mit mindestens dieser Größe erstellt (es ist einfach nicht praktikabel, zu große Einreichungen zu testen). .

"Template Haskell" ermöglicht die Generierung von Haskell-Code zur Kompilierungszeit mit Haskell und ist daher ein umfassender Vorprozessor.

Hier ist mein Versuch, parametrisiert durch einen beliebigen numerischen Ausdruck FOO:

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

Die Magie ist der Code im "Spleiß" $(...). Dies wird zur Kompilierungszeit ausgeführt, um einen Haskell-AST zu generieren, der anstelle des Spleißes auf den AST des Programms gepfropft wird.

In diesem Fall erstellen wir einen einfachen AST, der das Literal darstellt 0. Wir replizieren diesmal FOO, um eine Liste zu erstellen. Anschließend verwenden wir ListEdas Language.Haskell.THModul, um diese AST-Liste in einen großen AST zu verwandeln, der das Literal darstellt [0, 0, 0, 0, 0, ...].

Das resultierende Programm entspricht main = print [0, 0, 0, ...]mit FOOWiederholungen von 0.

So kompilieren Sie zu 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

Dies entspricht 83 Bytes (66 für den Haskell-Code und 17 für das -XTemplateHaskellArgument) plus der Länge von FOO.

Wir können das Compiler-Argument umgehen und kompilieren nur mit ghc, aber wir müssen {-# LANGUAGE TemplateHaskell#-}am Anfang setzen, was den Code auf 97 Bytes erhöht.

Hier sind einige Beispielausdrücke für FOOund die Größe der resultierenden Binärdatei:

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

Mir ging der Arbeitsspeicher aus, mit dem ich kompiliert habe (2^20).

Wir können auch eine unendliche Liste mit repeatanstelle replicate FOOvon erstellen, aber das verhindert, dass der Compiler anhält;)


46
Willkommen bei Programming Puzzles und Code Golf. Dies ist eine hervorragende Antwort, insbesondere für einen neuen Benutzer dieser Website. Wenn Sie Hilfe benötigen (was ich bezweifle), können Sie sich gerne an uns wenden.
wizzwizz4

3
@ wizzwizz4: Ja, das ist eine geniale Antwort. Es ist im Wesentlichen dasselbe wie meins, außer dass es in Haskell eine spezielle Compiler-Direktive erfordert, damit die Metaprogrammierung funktioniert. ;)
Mason Wheeler

2
Wenn ich mit GHC 7.8.3 kompiliere, erhalte ich "Nicht im Bereich: '<$>'" (ich setze den Code auf [...].replicate (2^10)<$>[|0|])). Ich habe keine Erfahrung mit Haskell. Irgendwelche Tipps zum Kompilieren?
Dave

38
Schade, dass Template-Haskell nicht faul genug ist, um eine unendliche ausführbare Datei zu streamen.
PyRulez

1
Hallo @ Dave, die <$>Funktion ist in Haskell weit verbreitet, wurde jedoch in GHC 7.10 nur in den "Auftakt" (die standardmäßig verfügbaren Funktionen) verschoben. Für frühere Versionen müssen Sie import Control.Applicative;nach der vorhandenen importAnweisung hinzufügen . Ich habe es gerade mit GHC 7.8.4 versucht und es funktioniert.
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;

Dies ist die in Templates implementierte Ackermann-Funktion . Ich kann mit h=a<4,2>::n;meinem kleinen Computer (6 GB) nicht kompilieren , habe es aber h=a<3,14>mit einer 26-MB-Ausgabedatei geschafft. Sie können die Konstanten so einstellen, dass sie an die Grenzen Ihrer Plattform stoßen. Eine Anleitung finden Sie im verknüpften Wikipedia-Artikel.

Erfordert ein -gFlag für GCC (da alle Debug-Symbole tatsächlich Speicherplatz belegen) und eine Schablonentiefe, die über dem Standard liegt. Meine Kompilierungszeile endete als

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

Plattforminformationen

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

Ich mag diese wirklich, bin mir aber nicht sicher, ob ich eine .o-Ausgabe akzeptieren kann, da ich ELF / .exe / etc gesagt habe. (Und das Kompilieren optimiert alles vollständig!). Immer noch +1 (und bestätigt)
Dave

4
Update: Wie Ben Voigt verweist auf seine Antwort aus, GCC auf Linux nicht erzeugen ELF - Dateien als .O Ausgang, und ich habe es gelungen , die <3,14> Variante mit ihm zu bestätigen, so yup - diese gültig ist.
Dave

17
Ich hatte erwartet, dass etwas Absurdes aus C ++ - Vorlagen kommt. Mit der Ackermann-Funktion habe ich nicht gerechnet.
Mark

Gibt Ihnen Fibonacci nicht einen kleineren Code und eine bessere Steuerung der Ausgabegröße?
Will Ness

1
Aber wir wollen größeren Code! Fibonacci hat fast die gleiche Größe wie reiner linearer Code (aber eine längere Kompilierungszeit als der lineare Code). Sie könnten sicherlich Spaß haben mit einem statischen Array von Größe A+Bin jeder Klasse, jetzt denke ich daran ...
Toby Speight

65

ASM, 61 Bytes (29 Bytes Quelle, 32 Bytes für Flags), 4.294.975.320 Bytes ausführbar

.globl main
main:
.zero 1<<32

Kompilieren mit gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold


5
1<<30ist gut genug für C. Da dies Assembler ist, ist die Größe in Bytes.
Viraptor

2
@viraptor Mein System verfügt über 32 GB RAM und zum Spaß habe ich versucht, Ihren Code zu erstellen. asschafft es zu übergeben ld, ldscheitert aber damit . Scheint nicht einmal -mcmodel=mediumzu helfen.
Ich werde nicht existieren Idonotexist

2
versuche die Verwendung von Linkern zu erzwingen gold: gcc -fuse-ld=gold ...kompiliert / verlinkt ... eek! Fertiggestellt in 1:29 (89 Sekunden) und einer Größe von 1.073.748.000 Bytes.
Lornix

2
Ich habe es endlich geschafft, es mit 64-Bit-Ubuntu 15.10 zusammenzubauen, mit Aufruf gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold. Schlussbilanz: 4,294,975,320 bytesMit 32 zusätzlichen Bytes zur Programmlänge für -mcmodel=large -Wl,-fuse-ld=gold. Bemerkenswert, dass der Header falsch ist; Die Quelle ist 29 Byte (ohne die zusätzlichen Flags hinzugefügt).
Mego

3
Durch das Erhöhen der Zuweisung auf habe 1<<33ich eine 8,589,942,616ausführbare Byte-Datei erhalten.
Mego

60

Hier ist meine C-Antwort aus dem Jahr 2005. Würde eine 16-TB-Binärdatei erzeugen, wenn Sie 16 TB RAM hätten (Sie haben keine).

struct indblock{
   uint32_t blocks[4096];
};

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

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

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

struct inode bbtinode;

int main(){}

19
Msgstr "Würde eine 16 TB Binärdatei erzeugen, wenn Sie 16 TB RAM hätten (das tun Sie nicht)." - Ich habe auch keine 16-TB-Festplatte! Ich kann das nicht wirklich bestätigen, aber es ist trotzdem cool.
Dave

5
Ich habe dies versehentlich entdeckt und sah, wie der Compiler umkippte, als der Adressraum knapp wurde.
Joshua

8
Bitte versuchen Sie NICHT, diesen Eintrag zu golfen. Golfen ist gegen die Absicht des Codebeispiels und es gibt sowieso keine Punkte-Vorteile, wenn Sie dies tun. Code ist bereits seit 2005 GPL-zertifiziert.
Joshua,

6
@BenVoigt Unabhängig davon ist das Bearbeiten des Codes anderer Benutzer hier niemals akzeptabel. Hinterlasse einen Kommentar, wenn es ein Problem gibt. Relevanter Metapost
Mego

2
@ Joshua: Überprüfen Sie die Markdown Diff. Mego hat nur den Markierungshinweis hinzugefügt.
n̴̖̋h̷͉̃a̷̭̿h̷̭̿d̸̡̅ẗ̵̨́

25

Normaler alter C-Präprozessor: 214 Byte Eingabe, 5 MB Ausgabe

Inspiriert von meinem realen Präprozessor scheitern hier .

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

Experimente zeigen, dass jede Stufe von #defines (wie erwartet) die Ausgabe ungefähr zehnmal größer macht. Da das Kompilieren dieses Beispiels mehr als eine Stunde dauerte, bin ich nie zu "G" übergegangen.


9
Dies ist ein bisschen wie eine XML-Bombe
ein Ohrwurm

9
Insbesondere handelt es sich um eine Implementierung der ursprünglichen "Billion Laughs".
Mittwoch,

Das ist verrückt und doch einfach.
Vahid Amiri

2
Wow, dies verursacht tatsächlich einen Segfault in GCC 4.9 und Clang. Welchen Compiler hast du benutzt?
Dave

1
@ Dave: Seltsam. Wenn ich mit make kompiliere, wird es kompiliert, aber wenn ich genau den Befehl eintippe, den make verwendet, stürzt es ab. Und es scheint nicht mit Umgebungsvariablen zu tun zu haben.
Thomas Padron-McCarthy

24

Java, 450 + 22 = 472 Byte Quelle, ~ 1 GB Klassendatei

B.java (Golfversion, Warnung beim Kompilieren)

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 (ungolfed version)

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

Zusammenstellung

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

Erläuterung

Diese Bombe verwendet Anmerkungsprozessoren. Es werden 2 Kompilierungsdurchläufe benötigt. Der erste Durchgang bildet die Prozessorklasse B. Während des zweiten Durchlaufs erstellt der Prozessor eine neue Quelldatei C.javaund kompiliert sie in eine C.classmit einer Größe von 1,073,141,162Bytes.

Es gibt verschiedene Einschränkungen beim Versuch, eine große Klassendatei zu erstellen:

  • Erstellen von Identifikatoren mehr als etwa 64k ergibt: error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool.
  • Das Erstellen von mehr als 64.000 Variablen / Funktionen führt zu folgenden Ergebnissen: error: too many constants
  • Die Codegröße einer Funktion ist auf ca. 64 KB beschränkt.
  • Es scheint ein allgemeines Limit (Bug?) Im Java-Compiler von etwa 1 GB für die .classDatei zu geben. Wenn ich zu erhöhen , 16380um 16390in dem obigen Code der Compiler nie zurückgibt.
  • Es gibt auch ein Limit von ca. 1 GB für die .javaDatei. Das Erhöhen 16380auf 16400im obigen Code führt zu: An exception has occurred in the compiler (1.8.0_66). Please file a bug ...gefolgt von a java.lang.IllegalArgumentException.

10
Ordentlich; Sie haben im Wesentlichen Ihren eigenen Präprozessor innerhalb der Größenbeschränkung in einer Sprache mit einem Compiler erstellt, der benutzerdefinierte Präprozessoren von Haus aus unterstützt. Es liegt innerhalb der Regeln. Die letzte Klasse war nur 0,5 GB für mich, aber ich kann die Methode bestätigen.
Dave

Ein weiteres Beispiel in Java habrahabr.ru/post/245333 - es verwendet verschachtelte try..finally(Code in finally-Block wird für normale und Ausnahmefälle dupliziert) und Initialisierungsblock (Code aus Initialisierungsblock wird an jeden Konstruktor angehängt)
Victor

Ich habe die ädurch eine ersetzt iund die Nummern angepasst. Jetzt sollte die Bombe auf jedem System eine 1-GB-Klasse ohne Codierungsprobleme erstellen. Es benötigt jedoch jetzt viel mehr Speicher.
Sleafar

? erweitert TypeElement?!?
Katze


22

C, 26-Byte-Quelle, 2.139.103.367-Byte-Ausgabe, gültiges Programm

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

Kompiliert mit: gcc cbomb.c -o cbomb(gcc version 4.6.3, Ubuntu 12.04, ~ 77 Sekunden)

Ich dachte, ich würde versuchen zu sehen, wie groß ich ein gültiges Programm machen könnte, ohne irgendwelche Befehlszeilenoptionen zu verwenden. Die Idee kam mir aus dieser Antwort: https://codegolf.stackexchange.com/a/69193/44946 von Digital Trauma. Lesen Sie die Kommentare dort, warum dies kompiliert wird.

So funktioniert es: Das constentfernt das Schreibflag von den Seiten im Segment, damit main ausgeführt werden kann. Dies 195ist der Intel-Maschinencode für eine Rücksendung. Und da die Intel-Architektur Little-Endian ist, ist dies das erste Byte. Das Programm wird mit dem Startcode beendet, der im eax-Register abgelegt ist, wahrscheinlich mit 0.

Es sind nur etwa 2 Gig, da der Linker 32-Bit-Werte mit Vorzeichen für Offsets verwendet. Es ist 8 MB kleiner als 2 GB, da der Compiler / Linker etwas Platz zum Arbeiten benötigt und dies das größte ist, das ich ohne Linker-Fehler bekommen könnte - ymmv.


3
Interessanterweise beträgt die Ausgabe 2.078.451 gziped Bytes mit einer maximalen Komprimierungsrate von 1029: 1.
Zakipu

20

Boo , 71 Bytes. Kompilierungszeit: 9 Minuten. 134.222.236 Byte ausführbar

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

Verwendet ein Makro R(für Wiederholung), um den Compiler zu veranlassen, die Inkrement-Anweisung beliebig oft zu multiplizieren. Es werden keine speziellen Compiler-Flags benötigt. Speichern Sie die Datei einfach als bomb.boound rufen Sie den Compiler mit booc bomb.booauf, um sie zu erstellen.


2**e-Was ist das? Versuchen Sie es 9**e!
wchargin

1
@WChargin: Das Schöne an der Metaprogrammierung ist, wie einfach Sie sie anpassen können!
Mason Wheeler

Ich habe ein bisschen Probleme bei der Installation von Boo ... Ich werde dies bestätigen, wenn ich es schaffe, es zu installieren!
Dave

@ Dave Was für Probleme hast du damit?
Mason Wheeler

16

Kotlin , 90-Byte-Quelle, 177416 Byte (173 KB) kompilierte JVM-Binärdatei

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

Technisch gesehen können Sie dies sogar noch verlängern, indem Sie den Ausdruck weiter verschachteln. Der Compiler stürzt jedoch mit einem StackOverflowFehler ab, wenn Sie die Rekursion erhöhen.


Ihre SI-Präfixe stimmen nicht überein. Ist das 177416 Kilobyte = 173 MB oder 177416 Bytes = 173 kB?
Ben Voigt

1
@BenVoigt Vielen Dank für den Hinweis: D
TheNumberOne

Beeindruckend, habe ein +1
J Atkin

Damit Kotlin 1.2.20 kompiliert werden kann, müssen wir eine Tiefe entfernen und es sind ~ 104kB. Welche Version hast du ursprünglich benutzt?
TWiStErRob

15

C ++, 214 Bytes (keine speziellen Kompilierungsoptionen erforderlich)

#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 handelt sich um eine recht einfache zweidimensionale Vorlagenrekursion (die Rekursionstiefe ergibt sich aus der Quadratwurzel der insgesamt ausgegebenen Vorlagen, sodass die Plattformgrenzen nicht überschritten werden) mit einer kleinen Menge statischer Daten in jeder Vorlage.

Generierte Objektdatei mit g++ 4.9.3 x86_64-pc-cygwin2567355421 Bytes (2.4GiB).

Wenn Sie den Anfangswert über 80 erhöhen, wird der Cygwin-GCC-Assembler unterbrochen (zu viele Segmente).

Auch 99999kann ersetzt werden durch 9<<19oder ähnliches für eine erhöhte Größe , ohne den Quellcode zu ändern ... aber ich glaube nicht , ich brauche mehr Speicherplatz zu verwenden , als ich schon bin;)


Bestätigt (in der Tat ist es 2,56 GB mit Clang), aber es benötigt ein -cKompilierungsflag, um den Linker zu stoppen (2 zusätzliche Bytes), und ich bin nicht sicher, ob ich .o-Ausgaben akzeptieren kann (nicht eine der aufgelisteten). Trotzdem gefällt es mir, also +1.
Dave

@ Dave: gcc .o-Dateien haben das ELF-Format, nicht wahr?
Ben Voigt

Nicht sicher. Sie beginnen nicht mit einer magischen ELF-Nummer, wenn ich sie generiere ... Ich werde es später untersuchen.
Dave

@ Dave: Nun, cygwin gcc generiert keine ELF-Datei. Linux gcc scheint (obwohl ich mir einen aus einem anderen Stück Code anschaue)
Ben Voigt am

Ja, GCC 5.2.1 auf Kubuntu generiert zwar eine ELF-Datei, aber es sind nur 9 MB! Ich bin nicht sicher, wie es gelungen ist, es im Vergleich zu den anderen Compilern so stark zu komprimieren. Vielleicht würde GCC 4.9 eine 2 GB ELF-Datei erstellen.
Dave

6

Scala - 70-Byte-Quelle, 22980842-Byte-Ergebnis (nach jar)

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

Dies erzeugt 9 5 (ungefähr 59.000) spezialisierte Klassendateien, die in ein Glas von ungefähr 23 MB gepackt werden. Sie können im Prinzip weitermachen, wenn Sie über ein Dateisystem verfügen, das mit so vielen Dateien und genügend Speicher umgehen kann.

(Wenn der Befehl jar enthalten sein muss, sind es 82 Byte.)


Ich konnte es nicht kompilieren: error: java.lang.OutOfMemoryError: GC overhead limit exceeded. Könnten Sie auch den erforderlichen Befehl für die Kompilierung dokumentieren?
P.Péter

@ P.Péter - Du musst dem Compiler mehr Speicher geben, zB habe scalac -J-Xmx12G X.scalaich das benutzt. Ich habe nicht getestet, wie viel es tatsächlich braucht.
Rex Kerr

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 foundLeider immer noch nicht kompiliert :( Können Sie die Scala- und Java-Version angeben (vielleicht auch die Plattform)? Ich habe scalac 2.9.2 und OpenJDK 1.8.0_66-internal-b17 unter Debian 8 x86-64 verwendet.
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 für den -cEingang gcc bomb.c -o bomb.o -c; Ausgabe: 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};

0

Boo, weit mehr als Sie erwarten können

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

Dies sieht aus wie die Antwort von Mason Wheeler mit ein paar kleinen Änderungen (??). Haben Sie die gleiche Antwort unabhängig voneinander erhalten, oder haben die von Ihnen geänderten Werte etwas Wichtiges an sich?
Dave

0

Python 3:

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

Tetrationsbombe


2
Sie sollten angeben, wie viele Bytes die Ausgabe enthält, um zu sehen, wie Ihr Eintrag mit anderen verglichen wird.
Sanchises

Willkommen bei PPCG! Offenbar haben Sie versehentlich zwei Konten erstellt und diese Antwort zweimal gepostet. Ich habe die andere Antwort entfernt. Wie Sanchises sagte, wird diese Herausforderung durch die Größe des kompilierten Programms bewertet . Daher sollten Sie diese Größe in Ihre Antwort aufnehmen, da dies die primäre Punktzahl ist. Beachten Sie auch, dass das eigentliche Programm nicht sehr groß ist, sondern nur der Ausdruck, den Sie im Speicher erstellen. Sie sollten sich also einen anderen Ansatz überlegen.
Martin Ender

1
@MartinEnder Da Python einige Ausdrücke zur Kompilierungszeit auswertet und Zahlen mit willkürlicher Genauigkeit speichert, wird dies (theoretisch) eine ziemlich große ausführbare Datei haben. Aber wie von Aleksi Torhamo (der die gleiche Technik für einen Teil seiner Antwort verwendet hat) bemerkt, liegt diese Grenze irgendwo bei 2 GB, daher würde ich erwarten, dass dieser Code wie geschrieben wahrscheinlich nicht kompiliert wird (obwohl ich ihn nicht überprüft habe) ). Wenn das OP es zum Kompilieren bringen und die kompilierte Größe bereitstellen kann (zusammen mit dem Befehl, der zum Generieren benötigt wird), ist es gültig. Die Ähnlichkeit mit Aleksis bestehender Antwort scheint mir ein Zufall zu sein.
Dave
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.