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

• If using a transpiler, does the output source code need to be under 512 bytes as well as the input source code? Jan 11, 2016 at 23:57
• Is repeated transpilation allowed?
– orlp
Jan 12, 2016 at 0:02
• @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)
– Dave
Jan 12, 2016 at 0:21
• @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.
– Dave
Jan 12, 2016 at 0:58
• @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.
– Dave
Jan 17, 2016 at 17:09

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

• Jan 12, 2016 at 1:19
• I'm playing against my solution here, but... you don't need a. You can just use main[1<<30]={1}; Jan 12, 2016 at 1:41
• 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. Jan 12, 2016 at 19:55
• >4gb? That escalated quickly Jan 13, 2016 at 1:28
• In case anyone else is wondering why this compiles: stackoverflow.com/questions/34764796/… Jan 13, 2016 at 11:40

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

• +1, but why don't (1<<19**8,)*2? 4GB is enough. Jan 14, 2016 at 10:38
• @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. :-) Jan 14, 2016 at 10:46
• 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!)
– Dave
Jan 17, 2016 at 17:22
• IIRC, python uses 30 bits per 32-bit word in its integer representation
– user16488
Oct 6, 2016 at 23:34
• @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! Feb 17, 2021 at 19:58

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

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

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 )

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


# 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

• 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).
– Dave
Oct 24, 2017 at 17:20

# 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}\$$).

### Credits

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

• Welcome to Code Golf, and nice first answer! Nov 24, 2021 at 13:28
• Thank you so much for the remark @AaroneousMiller ! Nov 24, 2021 at 13:29
• I don't really know much about C, but I'm curious how this works. Nov 24, 2021 at 13:30
• how large is the output file? Nov 24, 2021 at 14:05

# 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


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

• 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)
– Dave
Nov 25, 2021 at 20:40

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!

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



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