Construa uma bomba de compilador

372

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 -lmparte (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) .

Dave
fonte
Se estiver usando um transpiler, o código fonte de saída precisa ter menos de 512 bytes, assim como o código fonte de entrada?
Trichoplax
3
A transpilação repetida é permitida?
orlp 12/01
3
@ LegionMammal978 sim, tem que produzir um dos tipos de arquivo que eu especifiquei. Mas se você acha que encontrou algo que é mais máquina virtual do que linguagem interpretada, pergunte sobre isso especificamente e é possível que eu permita (é um pouco subjetivo, eu queria ser muito restritivo para começar, com a opção de abri-lo)
Dave
3
@trichoplax Eu não sabia disso, mas de algumas leituras parece que sim; compilar no bytecode do Python conta absolutamente. Portanto, para python, o tamanho da saída seria o tamanho total da soma de todos os seus arquivos pyc / pyo. Atualizarei a pergunta em breve com essas atualizações baseadas em comentários.
Dave
2
@MartinRosenau - WGroleau já fez uma pergunta semelhante; é padrão nos desafios de codificação que você pode usar qualquer coisa que já existia quando o desafio começou.
Dave

Respostas:

441

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 mainfunçã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=mediumsinalizador para o GCC. Os 15 bytes extras estão incluídos na pontuação, de acordo com as regras.

main[-1u]={1};

Não espere que esse código faça algo de bom quando executado.

Ajuntar com:

gcc -mcmodel=medium cbomb.c -o cbomb

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.

Devido à carga da CPU e da RAM, eu recomendo não fazer essa compilação em qualquer máquina remotamente relacionada à produção .

Trauma Digital
fonte
11
Os elementos
Digital Trauma
13
Estou jogando contra a minha solução aqui, mas ... você não precisa a. Você pode simplesmente usarmain[1<<30]={1};
viraptor
38
Oh meu. Isso é mau. X congelou por vários minutos tentando compilar esse código. Eu estava começando a procurar outro computador para voltar ao ssh e matar o processo gcc antes que ele finalmente voltasse à vida. Btw. Se você deseja um valor maior do que 1<<30então, 7<<28pode ser uma opção.
kasperd
33
> 4gb? Isso aumentou rapidamente
Wayne Werner
18
Caso alguém mais esteja se perguntando por que isso é compilado: stackoverflow.com/questions/34764796/…
TC
206

C #, aproximadamente 1 min para compilar, saída de 28 MB binária:

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

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érica X<A>, que possui uma classe interna Y. X<A>.Yherda X<Y>, portanto, X<A>.Ytambém tem uma classe interna Y, que é então X<A>.Y.Y. Isso também tem uma classe interna Y, e essa classe interna Ytem uma classe interna Yetc. 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, param Atem um tipo de X<A>.Y.
No class X<A> { class Y : X<Y> { Y.Y y;} }tipo, param Atem um tipo de X<X<A>.Y>.Y.
No class X<A> { class Y : X<Y> { Y.Y.Y y;} }tipo, param Atem um tipo de X<X<X<A>.Y>.Y>.Y.
No class X<A,B> { class Y : X<Y,Y> { Y y;} }tipo param Aé X<A,B>.Ye Bé X<A,B>.Y.
No class X<A> { class Y : X<Y> { Y.Y y;} }tipo param Aé X<X<A,B>.Y, X<A,B>.Y>.Ye Bé X<X<A,B>.Y, X<A,B>.Y>.Y.
No class X<A> { class Y : X<Y> { Y.Y.Y y;} }tipo param Aé X<X<X<A,B>.Y, X<A,B>.Y>.Y, X<X<A,B>.Y, X<A,B>.Y>.Y>.Ye Bé 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 Aque Eestá na Y.Y.Y.Y.Y.Y.Y.Y.Ydefinição 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 Você pode descobrir isso, mas precisa de muita paciência, e o senso comum não o ajudará aqui.

Vladimir Reshetnikov
fonte
14
É mais como o tipo de loucura que eu esperava! Parece que vou reinstalar o Mono…
Dave
31
Você pode fornecer uma explicação para esse efeito notório?
Odomontois
16
+1 por fazer mais do que apenas inicializar uma grande matriz.
precisa saber é o seguinte
6
Aqui está um exemplo usando o Try Roslyn e apenas 3 Ys .
Kobi
10
Eu vi essa pergunta e pensei imediatamente em você. Agradável!
Eric Lippert
154

Fonte Python 3, 13 bytes, 9.057.900.463 bytes (8,5GiB) .pyc-file

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

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)

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

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ímido 8*2**31, por isso 1<<19**8tem 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**31vezes, provavelmente. O número 4**7de 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.

Aleksi Torhamo
fonte
2
+1, mas por que não (1<<19**8,)*2? 4GB é suficiente.
Akangka 14/01
2
@ChristianIrwan: Sim, eu esqueci essa regra, só a percebi há alguns minutos atrás e ainda não descobri que tipo de edição devo fazer ainda. :-)
Aleksi Torhamo
1
Agradável. Como são apenas 13 bytes, finalmente temos um desafiante para a primeira resposta publicada! Eu só consegui confirmar 1<<18na 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!)
Dave
1
@ Dave: O tamanho exato pode depender da versão (1,5 GB soa estranho, não importa o quê); Eu estava usando o Python 3.3.5 e usado python -m py_compile asd.pypara gerar o arquivo .pyc.
Aleksi Torhamo 17/01
3
IIRC, python usa 30 bits por palavra de 32 bits em sua representação inteira #
130

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

"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:

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

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 esse FOOtempo para fazer uma lista e usamos ListEo Language.Haskell.THmó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, ...]com FOOrepetições de 0.

Para compilar no 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

Isso pesa 83 bytes (66 para o código Haskell e 17 para o -XTemplateHaskellargumento), mais o comprimento de FOO.

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 FOOe o tamanho do binário resultante:

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

Fiquei sem memória RAM ao compilar (2^20).

Também podemos fazer uma lista infinita, usando em repeatvez de replicate FOO, mas isso impede que o compilador pare;)

Warbo
fonte
46
Bem-vindo à programação de quebra-cabeças e código de golfe. Esta é uma resposta brilhante , especialmente para um novo usuário neste site. Se precisar de ajuda (o que duvido), não hesite em perguntar.
Wizzwizz4
3
@ wizzwizz4: Sim, é uma resposta brilhante. É essencialmente o mesmo que o meu, exceto que em Haskell requer uma diretiva de compilador especial para fazer a metaprogramação funcionar. ;)
Mason Wheeler
2
Ao compilar com o GHC 7.8.3, recebo "Fora do escopo: '<$>'" "(defino o código como [...].replicate (2^10)<$>[|0|])). Não tenho experiência com Haskell; alguma dica sobre como fazer isso compilar?
Dave
38
Pena que o haskell do modelo não é preguiçoso o suficiente para transmitir um executável infinito.
precisa saber é o seguinte
1
Olá @Dave, a <$>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á adicionar import Control.Applicative;após a importdeclaração existente. Eu apenas tentei com o GHC 7.8.4 e funciona.
Warbo 13/01/16
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;

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 consegui h=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 -gsinalizador 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 como

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

Informações da plataforma

g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Linux 3.13.0-46-generic #79-Ubuntu SMP x86_64 GNU/Linux
Toby Speight
fonte
Eu realmente gosto deste, mas não tenho certeza se posso aceitar uma saída .o, pois disse ELF / .exe / etc. (e compilar isso otimiza tudo!). Ainda assim, +1 (e confirmado)
Dave
4
Update: Como aponta Ben Voigt para fora em sua resposta, GCC em Linux não gerar arquivos ELF como .o saída, e eu tenho sido capaz de confirmar a variante <3,14> com ele, assim yup - isto é válido.
Dave
17
Eu esperava algo absurdo nos modelos C ++. Eu não estava esperando a função de Ackermann.
Mark
Fibonacci não fornecerá um código menor e melhor controle do tamanho da saída?
Will Ness
1
Mas queremos um código maior! Fibonacci fornece quase o mesmo tamanho que o código linear puro (mas maior tempo de compilação que o linear). Você certamente poderia se divertir com um conjunto estático de tamanho A+Bem cada classe, agora que penso nisso ...
Toby Speight
65

ASM, 61 bytes (fonte de 29 bytes, 32 bytes para sinalizadores), 4.294.975.320 bytes executáveis

.globl main
main:
.zero 1<<32

Ajuntar com gcc the_file.s -mcmodel=large -Wl,-fuse-ld=gold

viraptor
fonte
5
1<<30é bom o suficiente para C. Como esse é o assembler, o tamanho está em bytes.
viraptor
2
@viraptor Meu sistema tem 32 GB de RAM e, para chutes, tentei criar seu código. asconsegue entregar ld, mas ldfalha com isso . Nem -mcmodel=mediumparece ajudar.
existirá idonotexist em
2
tente forçar o uso do goldvinculador: gcc -fuse-ld=gold ...compila / vincula ... eek! Concluído em 1:29 (89 segundos) e tamanho de 1.073.748.000 bytes.
Lornix
2
Finalmente consegui montar isso no Ubuntu 15.10 de 64 bits, com invocação gcc -o g g.s -mcmodel=large -Wl,-fuse-ld=gold. Contagem final:, 4,294,975,320 bytescom 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).
Mego
3
Aumentando a alocação 1<<33, acabei com um 8,589,942,616byte executável.
Mego
60

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

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(){}
Joshua
fonte
19
"Produziria um binário de 16 TB se você tivesse 16 TB de RAM (você não)." - nem eu tenho um disco rígido de 16 TB! Eu realmente não posso verificar este, mas é legal mesmo assim.
Dave
5
Descobri este por acidente e vi o compilador tombar quando ficou sem espaço de endereço.
Joshua Joshua
8
Por favor, NÃO tente jogar golfe nesta entrada; o golfe derrota a intenção do exemplo de código e, de qualquer maneira, não há benefícios de pontuação. Código já está GPL a partir de 2005.
Joshua
6
@BenVoigt Independentemente disso, a edição do código de outras pessoas nunca é aceitável aqui. Deixe um comentário se houver algum problema. Meta post relevante: meta.codegolf.stackexchange.com/questions/1615/…
Mego
2
@ Josué: Verifique a diferença de descontos. Mego adicionou apenas a dica de destaque.
N
25

Pré-processador C simples antigo: entrada de 214 bytes, saída de 5 MB

Inspirado pelo meu pré-processador do mundo real falhar aqui .

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

As experiências mostram que cada nível de #defines 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".

Thomas Padron-McCarthy
fonte
9
Isso é como uma bomba xml
uma brincadeira
9
Especificamente, é uma implementação do original "Billion Laughs".
mınxomaτ
Isso é insano, mas simples.
Vahid Amiri 16/01
2
Uau, isso realmente causa um segfault no GCC 4.9 e Clang. Qual compilador você usou?
Dave
1
@ Dave: Estranho. Quando eu compilar usando o make, ele compila, mas se eu digitar exatamente o mesmo comando que o make usa, ele trava. E isso não parece estar relacionado a variáveis ​​de ambiente.
Thomas Padron-McCarthy
24

Java, 450 + 22 = origem de 472 bytes, arquivo de classe ~ 1 GB

B.java (versão para golfe, aviso durante a compilação)

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 (versão não destruída)

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

Compilação

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

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 origem C.javae o compila em C.classum tamanho de 1,073,141,162bytes.

Existem várias limitações ao tentar criar um arquivo de classe grande:

  • Criando identificadores de mais de cerca de 64k resulta em: error: UTF8 representation for string "iiiiiiiiiiiiiiiiiiii..." is too long for the constant pool.
  • A criação de mais de 64k variáveis ​​/ funções resulta em: error: too many constants
  • Há também um limite de cerca de 64k para o tamanho do código de uma função.
  • Parece haver um limite geral (bug?) No compilador java de cerca de 1 GB para o .classarquivo. Se eu aumentar 16380para 16390o código acima, o compilador nunca retornará.
  • Há também um limite de cerca de 1 GB para o .javaarquivo. Aumentar 16380para 16400o código acima resulta em: An exception has occurred in the compiler (1.8.0_66). Please file a bug ...seguido de a java.lang.IllegalArgumentException.
Sleafar
fonte
10
Arrumado; você essencialmente criou seu próprio pré-processador, dentro do limite de tamanho, em um idioma com um compilador que suporta nativamente pré-processadores personalizados. Está dentro das regras. A aula final foi de apenas 0,5 GB para mim, mas posso confirmar o método.
Dave
Outro exemplo em Java habrahabr.ru/post/245333 - ele usa nested 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)
Victor
Substituí o äpor um ie 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.
Sleafar
? estende TypeElement?!?
gato
1
@cat Veja aqui: angelikalanger.com/GenericsFAQ/FAQSections/…
Sleafar 9/16
22

C, fonte de 26 bytes, saída de 2.139.103.367 bytes, programa válido

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

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 constremove o sinalizador de gravação das páginas do segmento, para que o main possa ser executado. O 195é 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.

Zakipu
fonte
3
Como um aparte interessante, a saída é 2.078.451 bytes gziped com compressão máxima = taxa de compressão 1029: 1.
Zakipu
20

Boo , 71 bytes. Tempo de compilação: 9 minutos. Executável de 134.222.236 bytes

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

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 como bomb.booe chame o compilador booc bomb.boopara construí-lo.

Mason Wheeler
fonte
2**e-o que é isso? Experimente 9**e!
precisa saber é
1
@WChargin: A parte divertida da metaprogramação é a facilidade com que você pode personalizá-la!
Mason Wheeler
Estou com alguns problemas para instalar o boo… confirmo este quando conseguir instalá-lo!
Dave
@Dave Que problemas você está tendo com isso?
Mason Wheeler
16

Kotlin , origem de 90 bytes, 177416 bytes (173 KB) binário da JVM compilado

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

Tecnicamente, você pode tornar isso ainda mais longo, aninhando ainda mais a expressão. No entanto, o compilador falha com um StackOverflowerro se você aumentar a recursão.

O número um
fonte
Seus prefixos de SI não concordam. Isso significa 177416 kilobytes = 173 MB ou 177416 bytes = 173 kB?
Ben Voigt
1
@BenVoigt Obrigado por apontar isso: D
TheNumberOne
Impressionante, tenha +1
J Atkin
Para o Kotlin 1.2.20 compilar, precisamos remover uma profundidade e é ~ 104kB. Qual versão você usou originalmente?
TWiStErRob 23/01
15

C ++, 214 bytes (não são necessárias opções especiais de compilação)

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

É 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, 99999pode ser substituído por 9<<19ou 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;)

Ben Voigt
fonte
Confirmado (na verdade, é de 2,56 GB com clang), mas precisa de um -csinalizador 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.
Dave
@ Dave: os arquivos gcc .o são do formato ELF, não são?
Ben Voigt
Não tenho certeza. Eles não começam com um número mágico ELF quando eu os gerar ... investigarei mais tarde.
Dave
@ Dave: Bem, o cygwin gcc não está gerando um arquivo ELF. Linux gcc parece (embora eu estou olhando para um de uma peça diferente de código)
Ben Voigt
Sim, o GCC 5.2.1 no Kubuntu está realmente gerando um arquivo ELF, mas tem apenas 9 MB! Não tenho certeza de como ele conseguiu compactá-lo tanto em comparação com os outros compiladores. Talvez o GCC 4.9 crie um arquivo ELF de 2 GB.
Dave
6

Scala - fonte de 70 bytes, resultado de 22980842 bytes (após o jar)

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

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

Rex Kerr
fonte
Eu não poderia compilá-lo: error: java.lang.OutOfMemoryError: GC overhead limit exceeded. Você também pode documentar o comando necessário para a compilação?
P.Péter 18/01/16
@ P.Péter - Você precisa dar mais memória ao compilador, por exemplo, scalac -J-Xmx12G X.scalaé o que eu usei. Não testei quanto ele realmente precisa.
Rex Kerr
Ainda não está compilando, infelizmente :( 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 foundVocê 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.
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 para o -cna gcc bomb.c -o bomb.o -c; saída: 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};
H2CO3
fonte
0

Boo, muito mais do que você pode esperar disso

macro R(e as int):for i in range(9**e):yield R.Body
x = 0
R 99:++x
user75200
fonte
Parece a resposta de Mason Wheeler com algumas pequenas alterações (??). Você alcançou a mesma resposta de forma independente ou há algo importante nos valores alterados (se sim, edite a resposta para explicar por que eles são importantes).
Dave
0

Python 3:

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

Bomba de tetração

Ryan Burgert
fonte
2
Você deve indicar quantos bytes a saída é para ver como sua entrada se compara a outras.
Sanchises 29/03
Bem-vindo ao PPCG! Parece que você criou acidentalmente duas contas e postou esta resposta duas vezes. Eu removi a outra resposta. Como Sanchises disse, esse desafio é pontuado pelo tamanho do programa compilado . Portanto, você deve incluir esse tamanho na sua resposta, pois é a pontuação principal. Observe também que o programa atual não será muito grande, apenas a expressão que você está criando na memória; portanto, convém pensar em uma abordagem diferente.
Martin Ender
1
O @MartinEnder, devido à forma como o Python avalia algumas expressões em tempo de compilação e armazena números com precisão arbitrária, isso (em teoria) terá um executável bastante grande. Mas, como observado por Aleksi Torhamo (que usou a mesma técnica para parte de sua resposta), isso tem um limite em torno de 2 GB, então eu esperaria que esse código escrito provavelmente não seja compilado (embora eu não tenha verificado ) Se o OP conseguir compilar e publicar o tamanho compilado (junto com o comando necessário para gerá-lo), será válido. A semelhança com a resposta existente de Aleksi parece coincidência para mim.
31518 Dave