433
\$\begingroup\$

Introduction

You're probably familiar with zip bombs, XML bombs, etc. Put simply, they are (relatively) small files which produce enormous output when interpreted by naïve software. The challenge here is to abuse a compiler in the same way.

Challenge

Write some source code which occupies 512 bytes or less and which compiles into a file which occupies the most possible space. Largest output file wins!

Rules

OK, so there are a few important clarifications, definitions and restrictions;

  • The output of the compilation must be an ELF file, a Windows Portable Executable (.exe), or virtual bytecode for the JVM or .Net's CLR (other types of virtual bytecode are also likely to be OK if asked for). Update: Python's .pyc / .pyo output also counts.
  • If your language-of-choice can't be compiled directly into one of those formats, transpilation followed by compilation is also allowed (Update: you can transpile multiple times, just so long as you never use the same language more than once).
  • Your source code can consist of multiple files, and even resource files, but the summed size of all these files must not exceed 512 bytes.
  • You cannot use any other input than your source file(s) and the standard library of your language-of-choice. Static linking standard libraries is OK when it's supported. Specifically, no third party libraries or OS libraries.
  • It must be possible to invoke your compilation using a command or series of commands. If you require specific flags when compiling, these count towards your byte limit (e.g. if your compile line is gcc bomb.c -o bomb -O3 -lm, the -O3 -lm part (7 bytes) will be counted (note the initial leading space isn't counted).
  • Preprocessors are permitted only if they are a standard compilation option for your language.
  • The environment is up to you, but in the interests of making this verifiable, please stick to recent (i.e. available) compiler versions and operating systems (and obviously specify which you're using).
  • It must compile without errors (warnings are OK), and crashing the compiler doesn't count for anything.
  • What your program actually does is irrelevant, though it can't be anything malicious. It doesn't even have to be able to start.

Example 1

The C program

main(){return 1;}

Compiled with Apple LLVM version 7.0.2 (clang-700.1.81) on OS X 10.11 (64-bit):

clang bomb.c -o bomb -pg

Produces a file of 9228 bytes. The total source size is 17+3 (for the -pg) = 20 bytes, which is easily within size limit.

Example 2

The Brainfuck program:

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

Transpiled with awib to c with:

./awib < bomb.bf > bomb.c

Then compiled with Apple LLVM version 7.0.2 (clang-700.1.81) on OS X 10.11 (64-bit):

clang bomb.c

Produces a file of 8464 bytes. The total input here is 143 bytes (since @lang_c is the default for awib it didn't need to be added to the source file, and there are no special flags on either command).

Also note that in this case, the temporary bomb.c file is 802 bytes, but this counts towards neither the source size nor the output size.

Final Note

If an output of more than 4GB is achieved (perhaps if somebody finds a turing complete preprocessor), the competition will be for the smallest source which produces a file of at least that size (it's just not practical to test submissions which get too big).

\$\endgroup\$
27
  • \$\begingroup\$ If using a transpiler, does the output source code need to be under 512 bytes as well as the input source code? \$\endgroup\$ Commented Jan 11, 2016 at 23:57
  • 3
    \$\begingroup\$ Is repeated transpilation allowed? \$\endgroup\$
    – orlp
    Commented Jan 12, 2016 at 0:02
  • 3
    \$\begingroup\$ @LegionMammal978 yes it has to produce one of the file types I specified. But if you think you've found something which is more virtual-machine than interpreted-language, ask about it specifically and it's possible I'll allow it (it's a bit subjective so I wanted to be very restrictive to begin, with the option of opening it up) \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 0:21
  • 3
    \$\begingroup\$ @trichoplax I wasn't aware of that, but from some reading it looks like yes; compiling to Python bytecode absolutely counts. So for python, the output size would be the sum total size of all your pyc/pyo files. I'll update the question soon with these comment-based updates. \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 0:58
  • 2
    \$\begingroup\$ @MartinRosenau - WGroleau already asked a similar question; it's standard in coding challenges that you can use anything which already existed when the challenge began. \$\endgroup\$
    – Dave
    Commented Jan 17, 2016 at 17:09

23 Answers 23

503
+50
\$\begingroup\$

C, (14 + 15) = 29 byte source, 17,179,875,837 (16 GB) byte executable

Thanks to @viraptor for 6 bytes off.

Thanks to @hvd for 2 bytes off and executable size x4.

This defines the main function as a large array and initialises its first element. This causes GCC to store the entire array in the resulting executable.

Because this array is bigger than 2GB, we need to provide the -mcmodel=medium flag to GCC. The extra 15 bytes are included in the score, as per the rules.

main[-1u]={1};

Don't expect this code to do anything nice when run.

Compile with:

gcc -mcmodel=medium cbomb.c -o cbomb

It took me a while to get round to testing @hvd's suggestion - and to find a machine with enough juice to handle it. Eventually I found a old non-production RedHat 5.6 VM with 10GB RAM, 12GB swap, and /tmp set to a large local partition. GCC version is 4.1.2. Total compile time about 27 minutes.

Due to the CPU and RAM load, I recommend against doing this compile on any remotely production-related machine.

\$\endgroup\$
32
  • 12
    \$\begingroup\$ @Sparr Elements with missing values will be initialized to 0 \$\endgroup\$ Commented Jan 12, 2016 at 1:19
  • 14
    \$\begingroup\$ I'm playing against my solution here, but... you don't need a. You can just use main[1<<30]={1}; \$\endgroup\$
    – viraptor
    Commented Jan 12, 2016 at 1:41
  • 40
    \$\begingroup\$ Oh my. This is evil. X froze for several minutes trying to compile that code. I was starting to look for another computer to possibly ssh back in and kill the gcc process before it finally came back to life. Btw. If you want a larger value than 1<<30 then 7<<28 could be an option. \$\endgroup\$
    – kasperd
    Commented Jan 12, 2016 at 19:55
  • 37
    \$\begingroup\$ >4gb? That escalated quickly \$\endgroup\$ Commented Jan 13, 2016 at 1:28
  • 21
    \$\begingroup\$ In case anyone else is wondering why this compiles: stackoverflow.com/questions/34764796/… \$\endgroup\$
    – T. C.
    Commented Jan 13, 2016 at 11:40
226
\$\begingroup\$

Python 3, 13 byte source, 9,057,900,463 byte (8.5GiB) .pyc-file

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

Edit: Changed the code to the version above after I realized the rules say output size beyond 4GiB doesn't matter, and the code for this one is ever so slightly shorter; The previous code - and more importantly the explanation - can be found below.


Python 3, 16 byte source, >32TB .pyc-file (if you have enough memory, disk space and patience)

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

Explanation: Python 3 does constant folding, and you get big numbers fast with exponentation. The format used by .pyc files stores the length of the integer representation using 4 bytes, though, and in reality the limit seems to be more like 2**31, so using just exponentation to generate one big number, the limit seems to be generating a 2GB .pyc file from an 8 byte source. (19**8 is a bit shy of 8*2**31, so 1<<19**8 has a binary representation just under 2GB; the multiplication by eight is because we want bytes, not bits)

However, tuples are also immutable and multiplying a tuple is also constant folded, so we can duplicate that 2GB blob as many times as we want, up to at least 2**31 times, probably. The 4**7 to get to 32TB was chosen just because it was the first exponent I could find that beat the previous 16TB answer.

Unfortunately, with the memory I have on my own computer, I could test this only up to a multiplier of 2, ie. (1<<19**8,)*2, which generated a 8.5GB file, which I hope demonstrates that the answer is realistic (ie. the file size isn't limited to 2**32=4GB).

Also, I have no idea why the file size I got when testing was 8.5GB instead of the 4GB-ish I expected, and the file is big enough that I don't feel like poking around it at the moment.

\$\endgroup\$
10
  • 3
    \$\begingroup\$ +1, but why don't (1<<19**8,)*2? 4GB is enough. \$\endgroup\$
    – Xwtek
    Commented Jan 14, 2016 at 10:38
  • 2
    \$\begingroup\$ @ChristianIrwan: Yeah, I'd forgotten that rule, only realized it a few minutes ago and haven't figured out what kind of edit I should make yet. :-) \$\endgroup\$ Commented Jan 14, 2016 at 10:46
  • 1
    \$\begingroup\$ Nice. Since this is only 13 bytes, we finally have a challenger to the first-posted answer! I was only able to confirm 1<<18 on my machine (1.5GB) but I'll test it on linux later, where I expect it will work with the full 8GB (not going to try the 32TB version!) \$\endgroup\$
    – Dave
    Commented Jan 17, 2016 at 17:22
  • 3
    \$\begingroup\$ IIRC, python uses 30 bits per 32-bit word in its integer representation \$\endgroup\$
    – user16488
    Commented Oct 6, 2016 at 23:34
  • 4
    \$\begingroup\$ @AnshumanKumar: In Python interactive shell? If you put it into a variable (so eg. v = (1<<19**8,)*4**7), and you have enough free memory (a bit over 2GB), nothing much - it'll take a second or two to complete, and the process will use that much more memory. If you don't put it into a variable, Python will try to display the number, which means it needs to convert it to decimal first - which will take some time (and more memory) with a number that big. How long? Depends on the computer, but on the order of a year. But after that, it should finally print the multi-gigabyte output for you! \$\endgroup\$ Commented Feb 17, 2021 at 19:58
222
\$\begingroup\$

C#, about 1 min to compile, 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;}}

Adding more Y's will increase the size exponentially.

An explanation by Pharap as per @Odomontois' request:

This answer is abusing inheritance and type parameters to create recursion. To understand what's happening, it's easier to first simplify the problem. Consider class X<A> { class Y : X<Y> { Y y; } }, which generates the generic class X<A>, which has an inner class Y. X<A>.Y inherits X<Y>, hence X<A>.Y also has an inner class Y, which is then X<A>.Y.Y. This then also has an inner class Y, and that inner class Y has an inner class Y etc. This means that you can use scope resolution (.) ad infinitum, and every time you use it, the compiler has to deduce another level of inheritance and type parameterisation.

By adding additional type parameters, the work the compiler has to do at each stage is further increased.

Consider the following cases:
In class X<A> { class Y : X<Y> { Y y;} } type param A has a type of X<A>.Y.
In class X<A> { class Y : X<Y> { Y.Y y;} } type param A has a type of X<X<A>.Y>.Y.
In class X<A> { class Y : X<Y> { Y.Y.Y y;} } type param A has a type of X<X<X<A>.Y>.Y>.Y.
In class X<A,B> { class Y : X<Y,Y> { Y y;} } type param A is X<A,B>.Y and B is X<A,B>.Y.
In class X<A> { class Y : X<Y> { Y.Y y;} } type param A is X<X<A,B>.Y, X<A,B>.Y>.Y and B is X<X<A,B>.Y, X<A,B>.Y>.Y.
In class X<A> { class Y : X<Y> { Y.Y.Y y;} } type param A is X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y and B is X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y.

Following this pattern, one can only imagine1 the work the compiler would have to do to to deduce what A to E are in Y.Y.Y.Y.Y.Y.Y.Y.Y in the definition 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 You could figure it out, but you'd need a lot of patience, and intellisense won't help you out here.

\$\endgroup\$
15
  • 19
    \$\begingroup\$ This is more like the sort of insanity I was expecting! Looks like I'm off to reinstall Mono… \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 2:00
  • 31
    \$\begingroup\$ Can you provide an explanation of such notorious effect? \$\endgroup\$
    – Odomontois
    Commented Jan 12, 2016 at 8:58
  • 16
    \$\begingroup\$ +1 for doing more than just initializing a large array. \$\endgroup\$ Commented Jan 12, 2016 at 9:18
  • 6
    \$\begingroup\$ Here's an example using Try Roslyn and just 3 Ys. \$\endgroup\$
    – Kobi
    Commented Jan 12, 2016 at 12:21
  • 10
    \$\begingroup\$ I saw this question and immediately thought of you. Nice! \$\endgroup\$ Commented Jan 13, 2016 at 16:14
145
\$\begingroup\$

If an output of more than 4GB is achieved (perhaps if somebody finds a turing complete preprocessor), the competition will be for the smallest source which produces a file of at least that size (it's just not practical to test submissions which get too big).

"Template Haskell" allows Haskell code to be generated at compile-time using Haskell, and is hence a turing complete pre-processor.

Here's my attempt, parameterised by an arbitrary numerical expression FOO:

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

The magic is the code inside the "splice" $(...). This will be executed at compile time, to generate a Haskell AST, which is grafted on to the program's AST in place of the splice.

In this case, we make a simple AST representing the literal 0, we replicate this FOO times to make a list, then we use ListE from the Language.Haskell.TH module to turn this list of ASTs into one big AST, representing the literal [0, 0, 0, 0, 0, ...].

The resulting program is equivalent to main = print [0, 0, 0, ...] with FOO repetitions of 0.

To compile to 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

This weighs in at 83 bytes (66 for the Haskell code and 17 for the -XTemplateHaskell argument), plus the length of FOO.

We can avoid the compiler argument and just compile with ghc, but we have to put {-# LANGUAGE TemplateHaskell#-} at the beginning, which bumps the code up to 97 bytes.

Here are a few example expressions for FOO, and the size of the resulting binary:

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

I ran out of RAM compiling with (2^20).

We can also make an infinite list, using repeat instead of replicate FOO, but that prevents the compiler from halting ;)

\$\endgroup\$
12
  • 54
    \$\begingroup\$ Welcome to Programming Puzzles and Code Golf. This is a brilliant answer, especially for a new user to this site. If you need any help (which I doubt), feel free to ask. \$\endgroup\$
    – wizzwizz4
    Commented Jan 12, 2016 at 17:05
  • 3
    \$\begingroup\$ @wizzwizz4: Yeah, it is a brilliant answer. It's essentially the same as mine, except that in Haskell it requires a special compiler directive to make the metaprogramming work. ;) \$\endgroup\$ Commented Jan 12, 2016 at 17:14
  • 2
    \$\begingroup\$ When I compile with GHC 7.8.3 I get "Not in scope: ‘<$>’" (I set the code to [...].replicate (2^10)<$>[|0|])). I'm not experienced with Haskell; any hints on how to make this compile? \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 23:36
  • 45
    \$\begingroup\$ Too bad template haskell isn't lazy enough to stream out an infinite executable. \$\endgroup\$ Commented Jan 13, 2016 at 1:46
  • 2
    \$\begingroup\$ I came here to post something exactly like this. Well done. \$\endgroup\$ Commented Jan 13, 2016 at 12:15
92
\$\begingroup\$

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;

This is the Ackermann function implemented in templates. I'm not able to compile with h=a<4,2>::n; on my little (6GB) machine, but I did manage h=a<3,14> for a 26M output file. You can tune the constants to hit your platform's limits - see the linked Wikipedia article for guidance.

Requires -g flag to GCC (because it's all the debug symbols that actually consume any space), and a larger-than-default template depth. My compile line ended up as

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

Platform information

g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Linux 3.13.0-46-generic #79-Ubuntu SMP x86_64 GNU/Linux
\$\endgroup\$
6
  • \$\begingroup\$ I really like this one, but I'm not sure I can accept a .o output, since I did say ELF/.exe/etc. (and compiling this fully optimises it all out!). Still, +1 (and confirmed) \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 23:01
  • 4
    \$\begingroup\$ Update: As Ben Voigt points out on his answer, GCC on Linux does generate ELF files as .o output, and I've been able to confirm the <3,14> variant with it, so yup - this is valid. \$\endgroup\$
    – Dave
    Commented Jan 13, 2016 at 0:34
  • 23
    \$\begingroup\$ I was expecting something absurd to come out of C++ templates. I wasn't expecting the Ackermann function. \$\endgroup\$
    – Mark
    Commented Jan 13, 2016 at 9:42
  • \$\begingroup\$ won't Fibonacci give you a smaller code and better output size control? \$\endgroup\$
    – Will Ness
    Commented Jan 14, 2016 at 21:45
  • 1
    \$\begingroup\$ But we want bigger code! Fibonacci gives almost the same size as pure linear code (but longer compile time that the linear). You could certainly have fun with a static array of size A+B in each class, now I think of it... \$\endgroup\$ Commented Jan 15, 2016 at 13:40
68
\$\begingroup\$

Here's my C answer from 2005. Would produce a 16TB binary if you had 16TB RAM (you don't).

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(){}
\$\endgroup\$
18
  • 27
    \$\begingroup\$ "Would produce a 16TB binary if you had 16TB RAM (you don't)." - neither do I have a 16TB hard drive! I can't really verify this one, but it's cool nonetheless. \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 23:45
  • 7
    \$\begingroup\$ I discovered this one by accident and watched the compiler topple over when it ran out of address space. \$\endgroup\$
    – Joshua
    Commented Jan 12, 2016 at 23:57
  • 12
    \$\begingroup\$ Please do NOT attempt to golf this entry; golfing defeats the intent of the code sample and there are no score benefits to doing so anyway. Code is already GPL'd as of 2005. \$\endgroup\$
    – Joshua
    Commented Jan 13, 2016 at 2:23
  • 6
    \$\begingroup\$ @BenVoigt Regardless, editing other people's code is never acceptable here. Leave a comment if there's an issue. Relevant meta post: meta.codegolf.stackexchange.com/questions/1615/… \$\endgroup\$
    – user45941
    Commented Jan 14, 2016 at 20:27
  • 3
    \$\begingroup\$ I would assume that the 16TB of data is very very repetitive, therefor you should be able to put both a swapfile and the output file on a compressed FS and then be able to do this, but I'm not sure. \$\endgroup\$
    – Shelvacu
    Commented Jan 15, 2016 at 18:08
67
\$\begingroup\$

ASM, 61 bytes (29 bytes source, 32 bytes for flags), 4,294,975,320 bytes executable

.globl main
main:
.zero 1<<32

Compile with gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold

\$\endgroup\$
17
  • 6
    \$\begingroup\$ 1<<30 is good enough for C. Since this is assembler, the size is in bytes. \$\endgroup\$
    – viraptor
    Commented Jan 12, 2016 at 2:00
  • 2
    \$\begingroup\$ @viraptor My system has 32GB of RAM and for kicks I tried to build your code. as manages to hand off to ld, but ld fails with this. Not even -mcmodel=medium seems to help. \$\endgroup\$ Commented Jan 12, 2016 at 2:49
  • 2
    \$\begingroup\$ try forcing use of gold linker: gcc -fuse-ld=gold ... compiles/links... eek! Finished in 1:29 (89 seconds) and size of 1,073,748,000 bytes. \$\endgroup\$
    – lornix
    Commented Jan 12, 2016 at 7:47
  • 3
    \$\begingroup\$ I finally got this to assemble on 64-bit Ubuntu 15.10, with invocation gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold. Final tally: 4,294,975,320 bytes, with 32 extra bytes added to the program length for -mcmodel=large -Wl,-fuse-ld=gold. Worth noting that the header is incorrect; the source is 29 bytes (without the extra flags added). \$\endgroup\$
    – user45941
    Commented Jan 12, 2016 at 18:24
  • 3
    \$\begingroup\$ By bumping the allocation up to 1<<33, I ended up with a 8,589,942,616 byte executable. \$\endgroup\$
    – user45941
    Commented Jan 12, 2016 at 18:37
34
\$\begingroup\$

Plain old C preprocessor: 214 bytes input, 5MB output

Inspired by my real-world preprocessor fail here.

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

Experiments show that each level of #defines will (as expected) make the output approximately ten times larger. But since this example took more than an hour to compile, I never went on to "G".

\$\endgroup\$
7
  • 15
    \$\begingroup\$ This is kinda like an xml bomb \$\endgroup\$
    – an earwig
    Commented Jan 14, 2016 at 19:24
  • 15
    \$\begingroup\$ Specifically it is an implementation of the original "Billion Laughs". \$\endgroup\$
    – user42643
    Commented Jan 15, 2016 at 10:11
  • 3
    \$\begingroup\$ Wow, this actually causes a segfault in GCC 4.9 and Clang. Which compiler did you use? \$\endgroup\$
    – Dave
    Commented Jan 17, 2016 at 17:26
  • 1
    \$\begingroup\$ @Dave: Strange. When I compile using make, it compiles, but if I type in the exact same command that make uses, it crashes. And it doesn't seem to be related to environment variables. \$\endgroup\$ Commented Jan 18, 2016 at 1:45
  • 1
    \$\begingroup\$ Ironically, the Tiny C Complier (which you would expect to fail even faster than other compilers) actually compiles this successfully in 0.131 seconds on Linux Mint 20.1 Cinnamon. \$\endgroup\$ Commented Feb 17, 2021 at 15:28
30
\$\begingroup\$

Java, 450 + 22 = 472 bytes source, ~1GB class file

B.java (golfed version, warning during compilation)

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

Compilation

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

Explanation

This bomb uses Annotation Processors. It needs 2 compile passes. The first pass builds the processor class B. During the second pass the processor creates a new source file C.java, and compiles it to a C.class with a size of 1,073,141,162 bytes.

There are several limitations when trying to create a big class file:

  • Creating identifiers longer than about 64k results in: error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool.
  • Creating more than about 64k variables/functions results in: error: too many constants
  • There is also a limit of about 64k for the code size of a function.
  • There seems to be a general limit (bug?) in the java compiler of about 1GB for the .class file. If I increase 16380 to 16390 in the above code the compiler never returns.
  • There is also a limit of about 1GB for the .java file. Increasing 16380 to 16400 in the above code results in: An exception has occurred in the compiler (1.8.0_66). Please file a bug ... followed by a java.lang.IllegalArgumentException.
\$\endgroup\$
9
  • 16
    \$\begingroup\$ Neat; you've essentially made your own preprocessor, within the size limit, in a language with a compiler which natively supports custom preprocessors. It's within the rules. The final class was only 0.5GB for me, but I can confirm the method. \$\endgroup\$
    – Dave
    Commented Jan 14, 2016 at 0:17
  • \$\begingroup\$ Another example in Java habrahabr.ru/post/245333 - it uses nested try..finally (code in finally block is duplicated for normal and exceptional cases) and initializer block (code from initializer block is appended to each constructor) \$\endgroup\$
    – Victor
    Commented Jan 14, 2016 at 10:37
  • \$\begingroup\$ I replaced the ä by an i and adjusted the numbers. Now the bomb should create a 1GB class on any system without any encoding issues. However, it now needs a lot more memory. \$\endgroup\$
    – Sleafar
    Commented Jan 16, 2016 at 16:23
  • \$\begingroup\$ ? extends TypeElement?!? \$\endgroup\$
    – cat
    Commented Oct 9, 2016 at 14:54
  • 1
    \$\begingroup\$ @cat See here: angelikalanger.com/GenericsFAQ/FAQSections/… \$\endgroup\$
    – Sleafar
    Commented Oct 9, 2016 at 15:15
28
\$\begingroup\$

C, 26 byte source, 2,139,103,367 byte output, valid program

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

Compiled using: gcc cbomb.c -o cbomb (gcc version 4.6.3, Ubuntu 12.04, ~77 seconds)

I thought I'd try to see how large I could make a valid program without using any command line options. I got the idea from this answer: https://codegolf.stackexchange.com/a/69193/44946 by Digital Trauma. See the comments there as to why this compiles.

How it works: The const removes the write flag from the pages in the segment, so main can be executed. The 195 is the Intel machine code for a return. And since the Intel architecture is little-endian, this is the first byte. The program will exit with whatever the start up code put in the eax register, likely 0.

It's only about 2 gig because the linker is using 32 bit signed values for offsets. It's 8 meg smaller than 2 gig because the compiler/linker needs some space to work and this is the largest I could get it without linker errors - ymmv.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ As an interesting aside, the output is 2,078,451 bytes gziped with max compression = 1029:1 compression ratio. \$\endgroup\$
    – Zakipu
    Commented Jan 21, 2016 at 7:21
22
\$\begingroup\$

Boo, 71 bytes. Compile time: 9 minutes. 134,222,236 byte executable

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

Uses a macro R (for Repeat) to cause the compiler to multiply the increment statement an arbitrary number of times. No special compiler flags are needed; simply save the file as bomb.boo and invoke the compiler with booc bomb.boo to build it.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ 2**e—what is this? Try 9**e! \$\endgroup\$
    – wchargin
    Commented Jan 13, 2016 at 12:46
  • 1
    \$\begingroup\$ @WChargin: The fun thing about metaprogramming is how easily you can customize it! \$\endgroup\$ Commented Jan 13, 2016 at 13:08
  • \$\begingroup\$ I'm having a bit of trouble installing boo… I'll confirm this one when I manage to install it! \$\endgroup\$
    – Dave
    Commented Jan 14, 2016 at 0:20
  • \$\begingroup\$ @Dave What trouble are you having with it? \$\endgroup\$ Commented Jan 14, 2016 at 0:25
  • \$\begingroup\$ Sure is a scary language! \$\endgroup\$
    – SanguineL
    Commented Jun 5 at 13:11
18
\$\begingroup\$

Kotlin, 90 bytes source, 177416 bytes (173 KB) compiled JVM binary

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

Technically, you could make this even longer by nesting the expression further. However, the compiler crashes with a StackOverflow error if you increase the recursion.

\$\endgroup\$
4
  • \$\begingroup\$ Your SI prefixes don't agree. Is that 177416 kilobytes = 173 MB, or 177416 bytes = 173 kB? \$\endgroup\$
    – Ben Voigt
    Commented Jan 12, 2016 at 18:33
  • 1
    \$\begingroup\$ @BenVoigt Thank you for pointing that out :D \$\endgroup\$ Commented Jan 12, 2016 at 18:35
  • \$\begingroup\$ Impressive, have a +1 \$\endgroup\$
    – J Atkin
    Commented Jan 13, 2016 at 0:42
  • \$\begingroup\$ For Kotlin 1.2.20 to compile we need to remove one depth and it's ~104kB. Which version did you use originally? \$\endgroup\$
    – TWiStErRob
    Commented Jan 23, 2018 at 1:05
16
\$\begingroup\$

C++, 214 bytes (no special compile options needed)

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

It's a fairly straightforward two-dimensional template recursion (recursion depth goes as the square-root of total templates emitted, so won't exceed platform limits), with a small amount of static data in each one.

Generated object file with g++ 4.9.3 x86_64-pc-cygwin is 2567355421 bytes (2.4GiB).

Increasing the initial value above 80 breaks the cygwin gcc assembler (too many segments).

Also, 99999 can be replaced by 9<<19 or similar for increased size without changing the source code... but I don't think I need to use any more disk space than I already am ;)

\$\endgroup\$
9
  • \$\begingroup\$ Confirmed (in fact, it's 2.56GB with clang), but it needs a -c compile flag to stop the linker (2 extra bytes), and I'm not sure I can accept .o output (not one of the ones I listed). Still, I like it, so +1. \$\endgroup\$
    – Dave
    Commented Jan 12, 2016 at 23:29
  • \$\begingroup\$ @Dave: gcc .o files are ELF format aren't they? \$\endgroup\$
    – Ben Voigt
    Commented Jan 12, 2016 at 23:49
  • \$\begingroup\$ Not sure. They don't start with an ELF magic number when I generate them… I'll investigate later. \$\endgroup\$
    – Dave
    Commented Jan 13, 2016 at 0:01
  • \$\begingroup\$ @Dave: Well, cygwin gcc isn't generating an ELF file. Linux gcc seems to (although I'm looking at one from a different piece of code) \$\endgroup\$
    – Ben Voigt
    Commented Jan 13, 2016 at 0:17
  • \$\begingroup\$ Yes, GCC 5.2.1 on Kubuntu is indeed generating an ELF file, but it's only 9MB! Not sure how it's managed to compress it so much compared to the other compilers. Maybe GCC 4.9 would make a 2GB ELF file. \$\endgroup\$
    – Dave
    Commented Jan 13, 2016 at 0:28
7
\$\begingroup\$

Scala - 70 byte source, 22980842 byte result (after jar)

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

This produces 95 (about 59,000) specialized class files, which pack into a jar of about 23 MB. You can in principle keep going if you have a filesystem that can handle that many files and enough memory.

(If the jar command must be included, it's 82 bytes.)

\$\endgroup\$
4
  • \$\begingroup\$ I could not compile it: error: java.lang.OutOfMemoryError: GC overhead limit exceeded. Could you also document the required command for compilation? \$\endgroup\$
    – P.Péter
    Commented Jan 18, 2016 at 16:14
  • \$\begingroup\$ @P.Péter - You need to give the compiler more memory, e.g. scalac -J-Xmx12G X.scala is what I used. I didn't test how much it actually needs. \$\endgroup\$
    – Rex Kerr
    Commented Jan 18, 2016 at 21:16
  • \$\begingroup\$ still not compiling, sadly :( 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 Can you specify the scala and java version (maybe platform, too)? I used scalac 2.9.2 and OpenJDK 1.8.0_66-internal-b17, on debian 8 x86-64. \$\endgroup\$
    – P.Péter
    Commented Feb 1, 2016 at 12:41
  • \$\begingroup\$ 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 \$\endgroup\$
    – Rex Kerr
    Commented Feb 1, 2016 at 14:20
6
\$\begingroup\$

Swift for wasm, 7 byte source, 6326162 byte (6.3MB) wasm file

Not winning, but I'm adding this answer for its sheer absurdity:

print()

The Swift compiler does almost no dead code stripping (at least when compiling for wasm), so you get the entire standard library. The arguments to the print statement, any loops or recursion I added, etc barely seemed to matter. However, removing the print statement entirely shrunk the code size by a noticeable amount.

For reference, I used the wasm file generated by https://swiftwasm.org/, which seems to be using Swift 5.6 at the time of writing.

\$\endgroup\$
5
\$\begingroup\$

C, 284 bytes + 2 for the -c in gcc bomb.c -o bomb.o -c; output: 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};
\$\endgroup\$
4
\$\begingroup\$

Julia, 22 bytes (in memory)

0:9^9 .|>i->@eval 2^$i

Try it online!

It's quite easy to make a compilation bomb in Julia, it can easily happen accidentally. Here we use the fact that a^i has some trickery when i is a litteral integer, that allows a^2 to be turned into a*a, and a^-1 into inv(a). It means that there is a new compiled method of litteral_pow being compiled for each i. I'm pretty sure this would be at least 4GB but I don't know how to check it. This is only compiled in memory and not saved in a file though

Julia, 114 bytes (output in a .ji file)

using Pkg
pkg"generate A"
write("A/src/A.jl","module A
!(::Val{x}) where x=x
.!Val.(1:9^9)end")
pkg"dev A"
using A

(can't) Try it online! Try A online!

To save compiled code to a file, the function must be in a package, therefore we create a package A that has the culprit (the function !). Val(i) is of type Val{i}, so a new method is compiled for each i. The output file will be in ~/.julia/compiled/<version>/A/xxx.ji In my testing, each additional method adds at least 150 bytes (and growing, 182MB for 1M methods), which means 25M would be enough

in Julia 1.7, +2 bytes because pkg"dev ./A" is needed

Julia, 117 bytes (without writing files)

this is basically the same as the above, but with the files already there. This is slightly longer because of the uuid needed in Project.toml (this is taken care of in pkg"generate A")

file structure

A
├── src
│   └── A.jl
├── Project.toml
└── a.jl

Project.toml, 52 bytes

name="A"
uuid="8945f399-ba5e-44d3-9e17-ab2f7e467331"

src/A.jl, 47 bytes

module A
!(::Val{x}) where x=x
.!Val.(0:9^9)end

Try it online!

a.jl, 7 bytes

using A

command line options (in the A folder), +11 bytes

julia --project=. a.jl
\$\endgroup\$
1
  • \$\begingroup\$ Interesting that Julia won't produce output for a single file. Does it help that "Your source code can consist of multiple files, and even resource files, but the summed size of all these files must not exceed 512 bytes."? Looks like a chunk of the second example is just writing a file, which isn't necessary (no answers so far have needed it but the rule has been there since the start) \$\endgroup\$
    – Dave
    Commented Nov 25, 2021 at 20:40
4
\$\begingroup\$

Myxal 0.7.1, 46 source bytes + 2 bytes flag = 48 bytes, 2.042 MB compiled

~~~~~~~y¢aaaa¢bbbb¢cccc¢dddd¢eeee¢ffff¢gggg¢hh

Simple node alias recursion bomb. Adding more aliases make the JVM complain of a too large main method.

~~~~~~~y # A bunch of filter modifiers on the element 'y'
¢a       # Alias that to 'a'
aaa¢b    # 3 'a's = 'b' and so on...
bbb¢c
ccc¢d
ddd¢e
eee¢f
fff¢g
ggg¢h
h        # Run that final 'h'

Compiled with the -O flag to disable optimization, which also disables shrinking for some reason.

\$\endgroup\$
4
\$\begingroup\$

C, 54 bytes, ridiculously large executable

#include <inttypes.h>
uint64_t main[(uint64_t)~0]={~0};

Not exactly original, but much more devastating.

Inline but not portable version

unsigned long long main[~0ull]={~0};

I am NOT going to sacrifice my laptop just for this.

Explanation

uint64_t, unsigned long long, they're both unsigned 64-bit integers.

The tilde (~) is the bitwise NOT operator in C (it flips the bits of a value).

(uint64_t)0 is 0000000000000000000000000000000000000000000000000000000000000000 in binary.

By applying the bitwise NOT operator, we get a... big number (\$2^{64}-1\$).

Credits

Big thanks to user Digital Trauma for his original implementation. This answer is really just an expansion from that.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! \$\endgroup\$ Commented Nov 24, 2021 at 13:28
  • 1
    \$\begingroup\$ Thank you so much for the remark @AaroneousMiller ! \$\endgroup\$ Commented Nov 24, 2021 at 13:29
  • 1
    \$\begingroup\$ I don't really know much about C, but I'm curious how this works. \$\endgroup\$ Commented Nov 24, 2021 at 13:30
  • 1
    \$\begingroup\$ @AaroneousMiller I've updated the post with the explanation! Feel free to ask anything about this. \$\endgroup\$ Commented Nov 24, 2021 at 13:41
  • 1
    \$\begingroup\$ how large is the output file? \$\endgroup\$ Commented Nov 24, 2021 at 14:05
4
\$\begingroup\$

Rust, 42 bytes, 1.31 GB executable

fn main(){print!("{:?}",[0u8;9999999999])}

Does not require any specific compilation flags, you can just compile with rustc cbomb.rs.
Arrays of the format [x; s] where x is Copy and s has type usize and both have a value known at compile time are constructed during compilation and embedded in the binary, though the final executable is smaller than I would expect from this and I do not know what mechanism does that.
I couldn't make the size much larger than this on my laptop without LLVM or the linker crashing from non-language limitations.

Rust, 42 bytes, 18(?) EB executable (on a 64-bit system)

fn main(){print!("{:?}",[0u8;usize::MAX])}  

The array would have a size of 18 EB, but the final executable would probably be smaller. I can't afford this much RAM and storage space, so I haven't been able to test this. Maybe you can if you are in the future.

\$\endgroup\$
2
  • \$\begingroup\$ This is exactly expected behavior. You’re allocating static memory on stack and if you compiling static executable binary without relocation table, so you have to preserve it in the binary to make loader able to load you program almost as-is. \$\endgroup\$
    – Alex Koz.
    Commented Sep 23 at 11:22
  • 1
    \$\begingroup\$ @AlexKoz. correct, and this is an intended solution for the rules above. \$\endgroup\$
    – Eir Nym
    Commented Sep 23 at 11:25
3
\$\begingroup\$

Boo, way more than you can expect from this

macro R(e as int):for i in range(9**e):yield R.Body
x = 0
R 99:++x
\$\endgroup\$
1
  • \$\begingroup\$ This looks like Mason Wheeler's answer with a few small changes (??). Did you reach the same answer independently or is there something important in the values you changed (if so, please edit the answer to explain why they are important). \$\endgroup\$
    – Dave
    Commented Oct 24, 2017 at 17:20
2
\$\begingroup\$

PHP 7.1:

const X="x",Y=X.X.X.X.X.X.X.X,Z=Y.Y.Y.Y.Y.Y.Y.Y,A=Z.Z.Z.Z.Z.Z.Z.Z,B=A.A.A.A.A.A.A.A,C=B.B.B.B.B.B.B.B,D=C.C.C.C.C.C.C.C,E=D.D.D.D.D.D.D.D,F=E.E.E.E.E.E.E.E,G=F.F.F.F.F.F.F.F;

. is the concatenation operator, and PHP's compiler will try to do constant folding where possible, so it will construct a huge string and store it in PHP's internal bytecode. (I think you can get this written to a file with newer versions.) This is only as efficient as a classic XML entity bomb unfortunately. You'd need a few more repetitions to get to the gigabyte range.

The interesting part is that by default the worst that'll happen is seeing an error like:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 50331680 bytes) in Command line code on line 1

PHP's web-orientedness means it has a memory limit by default!

\$\endgroup\$
2
\$\begingroup\$

Dlang (ldc compiler)

command to build ldc -c t.d

GBS is count of gigabytes;

code of t.d:

import std;
enum GBS = 1;
void main(){
    static foreach(i; 0..2* GBS){
        mixin(text(q{static immutable a}, i,q{ = uint.max.BigInt << uint.max;}));
        mixin(text(q{a}, i, q{.writeln;}));
    }
}

Result of compiling

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! \$\endgroup\$ Commented Nov 24, 2021 at 15:58
  • 1
    \$\begingroup\$ can you explain how this works? From the looks of it I'm guessing it's constant folding like some of the Python answers? \$\endgroup\$
    – Dave
    Commented Nov 25, 2021 at 20:54
  • 1
    \$\begingroup\$ static immutable variables stored in binary file and static foreach is cycle which executed in compile time. \$\endgroup\$
    – Tynuk
    Commented Dec 21, 2021 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.