How to dismantle a compiler bomb

main[-1u]={1};

You have heard of "zip bombs" (a tiny ZIP file that decompresses to multiple gigabytes) and "XML bombs" (small XML file abusing the entities to consume lots of memory), and now there is a "compiler bomb" to follow suit.  The idea is quite similar -- the source code is only 14 bytes, but the generated executable will be over 16 GB in size.

Who wrote it?

The code is attributed to Stack Exchange user Digital Trauma.  It was posted here on January 12, 2016.

How does it work?

In the code main is not a function, but an array of ints.  The value of -1u, that is, negative one as unsigned, is exactly 0xFFFFFFFF -- the maximum value of unsigned int.  The array will contain 4294967295 integers, each with the size of four bytes, taking up 17179869180 bytes in total.

The important element of the code is the array initialization -- {1}. The first element of the array will be initialized to 1, and all the remaining elements will be set to 0.  It is necessary for the compiler to place the entire array inside the executable.  (Try removing the initialization and compiling the code by yourself.)

What is surprising is that main does not have to be a function.  You can throw just about anything called main at the compiler and it will produce a valid executable -- but don't expect much more than a segmentation fault when you run it.

Getting it to compile

The author advises to compile the code with gcc, as follows:

gcc -mcmodel=medium cbomb.c -o cbomb

Turns out 8 gigabytes of RAM is not enough -- the compilation fails with an error.

cbomb.c:1:1: warning: data definition has no type or storage class
    main[-1u]={1};
    ^~~~
cbomb.c:1:1: warning: type defaults to ‘int’ in declaration of ‘main’ [-Wimplicit-int]
/usr/bin/ld: final link failed: Memory exhausted
collect2: error: ld returned 1 exit status

Let's make a diet bomb

To consume a little bit less of the memory while still being able to play with the code, let's try and modify it a little bit.

int main[10000]={1};

This code should produce an executable with the array having the size of 10000 integers, that is, 40000 bytes.  Let's see this in practice!

% cc ./dietbomb.c
% wc -c a.out
48296 a.out
% ./a.out 
zsh: segmentation fault ./a.out

As you can see, the compiled binary is 48K in size and gives a beautiful segfault when ran.

An exercise for the reader

What happens when you move the array declaration to the inside of the main() function and why?