Introdução
Você provavelmente está familiarizado com bombas zip , bombas XML , etc. Simplificando, eles são arquivos (relativamente) pequenos que produzem resultados enormes quando interpretados por software ingênuo. O desafio aqui é abusar de um compilador da mesma maneira.
Desafio
Escreva um código-fonte que ocupe 512 bytes ou menos e que seja compilado em um arquivo que ocupe o maior espaço possível. Maior arquivo de saída vence!
Regras
OK, existem alguns esclarecimentos, definições e restrições importantes;
- A saída da compilação deve ser um arquivo ELF , um executável portátil do Windows (.exe) ou bytecode virtual para a JVM ou o CLR da .Net (é provável que outros tipos de bytecode virtual também estejam OK se solicitado). Atualização: A saída .pyc / .pyo do Python também conta .
- Se o seu idioma de escolha não puder ser compilado diretamente em um desses formatos, a transpilação seguida da compilação também será permitida ( atualização: você pode transpilar várias vezes, desde que nunca use o mesmo idioma mais de uma vez ).
- Seu código-fonte pode consistir em vários arquivos e até arquivos de recursos, mas o tamanho total de todos esses arquivos não deve exceder 512 bytes.
- Você não pode usar nenhuma outra entrada além do (s) arquivo (s) de origem e a biblioteca padrão do seu idioma de escolha. As bibliotecas padrão de vinculação estática estão OK quando suportadas. Especificamente, nenhuma biblioteca de terceiros ou bibliotecas de SO.
- Deve ser possível chamar sua compilação usando um comando ou uma série de comandos. Se você precisar de sinalizadores específicos ao compilar, estes serão contados no limite de bytes (por exemplo, se sua linha de compilação for
gcc bomb.c -o bomb -O3 -lm
, a-O3 -lm
parte (7 bytes) será contada (observe que o espaço inicial inicial não é contado). - Os pré-processadores são permitidos apenas se forem uma opção de compilação padrão para o seu idioma.
- O ambiente é com você, mas no interesse de tornar isso verificável, atenha-se às versões recentes (disponíveis) do compilador e sistemas operacionais (e, obviamente, especifique qual você está usando).
- Ele deve ser compilado sem erros (os avisos são válidos) e travar o compilador não conta para nada.
- O que seu programa realmente faz é irrelevante, embora não possa ser nada malicioso. Nem precisa ser capaz de começar.
Exemplo 1
O programa C
main(){return 1;}
Compilado Apple LLVM version 7.0.2 (clang-700.1.81)
no OS X 10.11 (64 bits):
clang bomb.c -o bomb -pg
Produz um arquivo de 9228 bytes. O tamanho total da fonte é 17 + 3 (para o -pg
) = 20 bytes, o que está facilmente dentro do limite de tamanho.
Exemplo 2
O programa Brainfuck:
++++++[->++++++++++++<]>.----[--<+++>]<-.+++++++..+++.[--->+<]>-----.--
-[-<+++>]<.---[--->++++<]>-.+++.------.--------.-[---<+>]<.[--->+<]>-.
Transpilado com awib para c com:
./awib < bomb.bf > bomb.c
Em seguida, compilado Apple LLVM version 7.0.2 (clang-700.1.81)
no OS X 10.11 (64 bits):
clang bomb.c
Produz um arquivo de 8464 bytes. A entrada total aqui é de 143 bytes (já que @lang_c
é o padrão para o awib, ele não precisou ser adicionado ao arquivo de origem e não há sinalizadores especiais em nenhum dos comandos).
Observe também que, nesse caso, o arquivo bomb.c temporário tem 802 bytes, mas isso não conta para o tamanho da fonte nem do tamanho da saída.
Nota final
Se uma saída de mais de 4 GB for alcançada (talvez se alguém encontrar um pré-processador completo), a competição será pela menor fonte que produzir um arquivo com pelo menos esse tamanho (não é prático testar envios muito grandes) .
Respostas:
C, (14 + 15) = fonte de 29 bytes, executável de 17.179.875.837 (16 GB) bytes
Graças a @viraptor por 6 bytes de desconto.
Graças a @hvd por 2 bytes de desconto e tamanho executável x4.
Isso define a
main
função como uma matriz grande e inicializa seu primeiro elemento. Isso faz com que o GCC armazene toda a matriz no executável resultante.Como esse array é maior que 2 GB, precisamos fornecer o
-mcmodel=medium
sinalizador para o GCC. Os 15 bytes extras estão incluídos na pontuação, de acordo com as regras.Não espere que esse código faça algo de bom quando executado.
Ajuntar com:
Levei um tempo para testar a sugestão da @ hvd - e encontrar uma máquina com suco suficiente para lidar com isso. Eventualmente, encontrei uma VM RedHat 5.6 antiga que não era de produção, com 10 GB de RAM, troca de 12 GB e / tmp definida para uma grande partição local. A versão do GCC é 4.1.2. Tempo total de compilação cerca de 27 minutos.
fonte
a
. Você pode simplesmente usarmain[1<<30]={1};
1<<30
então,7<<28
pode ser uma opção.C #, aproximadamente 1 min para compilar, saída de 28 MB binária:
A adição de mais Y's aumentará exponencialmente o tamanho.
Uma explicação de Pharap, conforme solicitação do @Odomontois ':
Esta resposta está abusando dos parâmetros de herança e tipo para criar recursão. Para entender o que está acontecendo, é mais fácil simplificar o problema. Considere
class X<A> { class Y : X<Y> { Y y; } }
, o que gera a classe genéricaX<A>
, que possui uma classe internaY
.X<A>.Y
herdaX<Y>
, portanto,X<A>.Y
também tem uma classe internaY
, que é entãoX<A>.Y.Y
. Isso também tem uma classe internaY
, e essa classe internaY
tem uma classe internaY
etc. Isso significa que você pode usar a resolução do escopo (.
) ad infinitum e toda vez que usá-la, o compilador deve deduzir outro nível de herança e parametrização de tipo .Ao adicionar parâmetros de tipo adicionais, o trabalho que o compilador deve realizar em cada estágio é aumentado.
Considere os seguintes casos:
No
class X<A> { class Y : X<Y> { Y y;} }
tipo, paramA
tem um tipo deX<A>.Y
.No
class X<A> { class Y : X<Y> { Y.Y y;} }
tipo, paramA
tem um tipo deX<X<A>.Y>.Y
.No
class X<A> { class Y : X<Y> { Y.Y.Y y;} }
tipo, paramA
tem um tipo deX<X<X<A>.Y>.Y>.Y
.No
class X<A,B> { class Y : X<Y,Y> { Y y;} }
tipo paramA
éX<A,B>.Y
eB
éX<A,B>.Y
.No
class X<A> { class Y : X<Y> { Y.Y y;} }
tipo paramA
éX<X<A,B>.Y, X<A,B>.Y>.Y
eB
éX<X<A,B>.Y, X<A,B>.Y>.Y
.No
class X<A> { class Y : X<Y> { Y.Y.Y y;} }
tipo paramA
éX<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y
eB
éX<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Y
.Seguindo esse padrão, só podemos imaginar 1 o trabalho que o compilador teria que fazer para deduzir o
A
queE
está naY.Y.Y.Y.Y.Y.Y.Y.Y
definiçãoclass 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 Você pode descobrir isso, mas precisa de muita paciência, e o senso comum não o ajudará aqui.
fonte
Y
s .Fonte Python 3, 13 bytes, 9.057.900.463 bytes (8,5GiB) .pyc-file
Editar : Alterei o código para a versão acima depois que percebi que as regras dizem que o tamanho da saída além do 4GiB não importa, e o código para este é cada vez mais curto; O código anterior - e mais importante a explicação - pode ser encontrado abaixo.
Fonte Python 3, 16 bytes,> 32TB .pyc-file (se você tiver memória suficiente, espaço em disco e paciência)
Explicação: O Python 3 faz dobragem constante e você obtém grandes números rapidamente com a exponenciação. No entanto, o formato usado pelos arquivos .pyc armazena o comprimento da representação inteira usando 4 bytes e, na realidade, o limite parece ser mais semelhante
2**31
; portanto, usando apenas a exponentação para gerar um número grande, o limite parece estar gerando 2 GB. arquivo pyc de uma fonte de 8 bytes. (19**8
é um pouco tímido8*2**31
, por isso1<<19**8
tem uma representação binária de menos de 2 GB; a multiplicação por oito é porque queremos bytes, não bits)No entanto, as tuplas também são imutáveis e a multiplicação de uma tupla também é dobrada constantemente, para que possamos duplicar esse blob de 2 GB quantas vezes quisermos, até pelo menos
2**31
vezes, provavelmente. O número4**7
de 32 TB foi escolhido apenas porque foi o primeiro expoente que pude encontrar que superou a resposta anterior de 16 TB.Infelizmente, com a memória que tenho no meu computador, eu poderia testar isso apenas até um multiplicador de 2, ou seja.
(1<<19**8,)*2
, que gerou um arquivo de 8,5 GB, que espero demonstre que a resposta é realista (ou seja, o tamanho do arquivo não está limitado a 2 ** 32 = 4 GB).Além disso, não tenho idéia de por que o tamanho do arquivo que obtive durante os testes foi de 8,5 GB em vez dos 4 GB que eu esperava, e o arquivo é grande o suficiente para que eu não sinta vontade de procurá-lo no momento.
fonte
(1<<19**8,)*2
? 4GB é suficiente.1<<18
na minha máquina (1,5 GB), mas testarei no linux mais tarde, onde espero que funcione com os 8 GB completos (não vou tentar a versão de 32 TB!)python -m py_compile asd.py
para gerar o arquivo .pyc."Template Haskell" permite que o código Haskell seja gerado em tempo de compilação usando Haskell e, portanto, é um pré-processador completo.
Aqui está minha tentativa, parametrizada por uma expressão numérica arbitrária
FOO
:A mágica é o código dentro da "emenda"
$(...)
. Isso será executado em tempo de compilação, para gerar um Haskell AST, que é enxertado no AST do programa no lugar da emenda.Nesse caso, criamos um AST simples representando o literal
0
, replicamos esseFOO
tempo para fazer uma lista e usamosListE
oLanguage.Haskell.TH
módulo para transformar essa lista de ASTs em um grande AST, representando o literal[0, 0, 0, 0, 0, ...]
.O programa resultante é equivalente a
main = print [0, 0, 0, ...]
comFOO
repetições de0
.Para compilar no ELF:
Isso pesa 83 bytes (66 para o código Haskell e 17 para o
-XTemplateHaskell
argumento), mais o comprimento deFOO
.Podemos evitar o argumento do compilador e apenas compilar
ghc
, mas temos que colocar{-# LANGUAGE TemplateHaskell#-}
no início, que aumenta o código em até 97 bytes.Aqui estão alguns exemplos de expressões para
FOO
e o tamanho do binário resultante:Fiquei sem memória RAM ao compilar
(2^20)
.Também podemos fazer uma lista infinita, usando em
repeat
vez dereplicate FOO
, mas isso impede que o compilador pare;)fonte
[...].replicate (2^10)<$>[|0|])
). Não tenho experiência com Haskell; alguma dica sobre como fazer isso compilar?<$>
função é amplamente usada em Haskell, mas foi movida apenas para o "prelúdio" (o conjunto de funções disponíveis por padrão) no GHC 7.10. Para versões anteriores, você precisará adicionarimport Control.Applicative;
após aimport
declaração existente. Eu apenas tentei com o GHC 7.8.4 e funciona.C ++, 250 + 26 = 276 bytes
Essa é a função Ackermann implementada em modelos. Não consigo compilar
h=a<4,2>::n;
na minha pequena máquina (6 GB), mas conseguih=a<3,14>
obter um arquivo de saída de 26 milhões. Você pode ajustar as constantes para atingir os limites da sua plataforma - consulte o artigo vinculado da Wikipedia para obter orientação.Requer
-g
sinalizador para o GCC (porque são todos os símbolos de depuração que realmente consomem espaço) e uma profundidade de modelo maior que o padrão. Minha linha de compilação acabou comoInformações da plataforma
fonte
A+B
em cada classe, agora que penso nisso ...ASM, 61 bytes (fonte de 29 bytes, 32 bytes para sinalizadores), 4.294.975.320 bytes executáveis
Ajuntar com
gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold
fonte
1<<30
é bom o suficiente para C. Como esse é o assembler, o tamanho está em bytes.as
consegue entregarld
, masld
falha com isso . Nem-mcmodel=medium
parece ajudar.gold
vinculador:gcc -fuse-ld=gold ...
compila / vincula ... eek! Concluído em 1:29 (89 segundos) e tamanho de 1.073.748.000 bytes.gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold
. Contagem final:,4,294,975,320 bytes
com 32 bytes extras adicionados ao comprimento do programa para-mcmodel=large -Wl,-fuse-ld=gold
. Vale a pena notar que o cabeçalho está incorreto; a fonte é de 29 bytes (sem os sinalizadores extras adicionados).1<<33
, acabei com um8,589,942,616
byte executável.Aqui está a minha resposta C de 2005. Produziria um binário de 16 TB se você tivesse 16 TB de RAM (você não).
fonte
Pré-processador C simples antigo: entrada de 214 bytes, saída de 5 MB
Inspirado pelo meu pré-processador do mundo real falhar aqui .
As experiências mostram que cada nível de
#define
s aumentará (como esperado) a produção aproximadamente dez vezes maior. Mas como esse exemplo levou mais de uma hora para compilar, nunca fui para "G".fonte
Java, 450 + 22 = origem de 472 bytes, arquivo de classe ~ 1 GB
B.java (versão para golfe, aviso durante a compilação)
B.java (versão não destruída)
Compilação
Explicação
Esta bomba usa processadores de anotação. Ele precisa de 2 passes de compilação. A primeira passagem cria a classe do processador
B
. Durante a segunda passagem, o processador cria um novo arquivo de origemC.java
e o compila emC.class
um tamanho de1,073,141,162
bytes.Existem várias limitações ao tentar criar um arquivo de classe grande:
error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool
.error: too many constants
.class
arquivo. Se eu aumentar16380
para16390
o código acima, o compilador nunca retornará..java
arquivo. Aumentar16380
para16400
o código acima resulta em:An exception has occurred in the compiler (1.8.0_66). Please file a bug ...
seguido de ajava.lang.IllegalArgumentException
.fonte
try..finally
(código no bloco finally é duplicado para casos normais e excepcionais) e bloco inicializador (código do bloco inicializador é anexado a cada construtor)ä
por umi
e ajustei os números. Agora a bomba deve criar uma classe de 1 GB em qualquer sistema sem problemas de codificação. No entanto, agora ele precisa de muito mais memória.C, fonte de 26 bytes, saída de 2.139.103.367 bytes, programa válido
Compilado usando:
gcc cbomb.c -o cbomb
(gcc versão 4.6.3, Ubuntu 12.04, ~ 77 segundos)Eu pensei em tentar ver o quão grande eu poderia criar um programa válido sem usar nenhuma opção de linha de comando. Eu obtive a ideia desta resposta: https://codegolf.stackexchange.com/a/69193/44946 da Digital Trauma. Veja os comentários sobre por que isso é compilado.
Como funciona: O
const
remove o sinalizador de gravação das páginas do segmento, para que o main possa ser executado. O195
é o código da máquina Intel para retorno. E como a arquitetura Intel é pouco endian, esse é o primeiro byte. O programa será encerrado com qualquer código de inicialização inserido no registro eax, provavelmente 0.É apenas cerca de 2 GB, porque o vinculador está usando valores assinados de 32 bits para compensações. É 8 meg menor que 2 gig porque o compilador / vinculador precisa de algum espaço para funcionar e este é o maior que eu poderia obtê-lo sem erros no vinculador - ymmv.
fonte
Boo , 71 bytes. Tempo de compilação: 9 minutos. Executável de 134.222.236 bytes
Usa uma macro
R
(para Repetir) para fazer com que o compilador multiplique a instrução de incremento um número arbitrário de vezes. Nenhum sinalizador especial do compilador é necessário; simplesmente salve o arquivo comobomb.boo
e chame o compiladorbooc bomb.boo
para construí-lo.fonte
2**e
-o que é isso? Experimente9**e
!Kotlin , origem de 90 bytes, 177416 bytes (173 KB) binário da JVM compilado
Tecnicamente, você pode tornar isso ainda mais longo, aninhando ainda mais a expressão. No entanto, o compilador falha com um
StackOverflow
erro se você aumentar a recursão.fonte
C ++, 214 bytes (não são necessárias opções especiais de compilação)
É uma recursão de modelo bidimensional bastante direta (a profundidade da recursão é a raiz quadrada do total de modelos emitidos, portanto não excede os limites da plataforma), com uma pequena quantidade de dados estáticos em cada um.
O arquivo de objeto gerado
g++ 4.9.3 x86_64-pc-cygwin
é de 2567355421 bytes (2,4GiB).Aumentar o valor inicial acima de 80 interrompe o assembler do cygwin gcc (muitos segmentos).
Além disso,
99999
pode ser substituído por9<<19
ou similar para aumentar o tamanho sem alterar o código-fonte ... mas acho que não preciso usar mais espaço em disco do que já sou;)fonte
-c
sinalizador de compilação para parar o vinculador (2 bytes extras), e não tenho certeza se posso aceitar a saída .o (não uma das listadas). Ainda assim, eu gosto, então +1.Scala - fonte de 70 bytes, resultado de 22980842 bytes (após o jar)
Isso produz 9 5 (cerca de 59.000) arquivos de classe especializados, que são compactados em um pote de cerca de 23 MB. Em princípio, você pode continuar se tiver um sistema de arquivos capaz de lidar com tantos arquivos e memória suficiente.
(Se o comando jar precisar ser incluído, são 82 bytes.)
fonte
error: java.lang.OutOfMemoryError: GC overhead limit exceeded
. Você também pode documentar o comando necessário para a compilação?scalac -J-Xmx12G X.scala
é o que eu usei. Não testei quanto ele realmente precisa.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
Você pode especificar a versão scala e java (talvez também a plataforma)? Eu usei o scalac 2.9.2 e o OpenJDK 1.8.0_66-internal-b17, no debian 8 x86-64.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
C, 284 bytes + 2 para o
-c
nagcc bomb.c -o bomb.o -c
; saída: 2 147 484 052 bytesfonte
Boo, muito mais do que você pode esperar disso
fonte
Python 3:
Bomba de tetração
fonte