Java: int array inicializa com elementos diferentes de zero

130

De acordo com o JLS, uma intmatriz deve ser preenchida por zeros logo após a inicialização. No entanto, estou diante de uma situação em que não é. Esse comportamento ocorre primeiro no JDK 7u4 e também em todas as atualizações posteriores (eu uso a implementação de 64 bits). O código a seguir gera uma exceção:

public static void main(String[] args) {
        int[] a;
        int n = 0;
        for (int i = 0; i < 100000000; ++i) {
            a = new int[10];
            for (int f : a)
                if (f != 0)
                  throw new RuntimeException("Array just after allocation: "+ Arrays.toString(a));
            Arrays.fill(a, 0);
            for (int j = 0; j < a.length; ++j)
                a[j] = (n - j)*i;
            for (int f : a)
                n += f;
        }
        System.out.println(n);
    }

A exceção ocorre após a JVM executar a compilação do bloco de código e não surge com o -Xintsinalizador. Além disso, a Arrays.fill(...)instrução (como todas as outras instruções neste código) é necessária e a exceção não ocorre se estiver ausente. É claro que esse possível bug está associado a alguma otimização da JVM. Alguma idéia para a razão de tal comportamento?

Atualização:
Eu vejo esse comportamento na VM do servidor HotSpot de 64 bits, versão Java de 1.7.0_04 a 1.7.0_10 no Gentoo Linux, Debian Linux (versão do kernel 3.0) e MacOS Lion. Este erro sempre pode ser reproduzido com o código acima. Não testei esse problema com um JDK de 32 bits ou no Windows. Já enviei um relatório de bug para o Oracle (id 7196857) e ele aparecerá no banco de dados público de bug do Oracle em alguns dias.

Atualização: a
Oracle publicou esse bug em seu banco de dados público: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857

Stanislav Poslavsky
fonte
15
Eu diria bug na implementação se ele não está seguindo a especificação
Petesh
12
Como você tem um exemplo bem definido que reproduz o problema de maneira confiável (pelo menos em algumas plataformas), você considerou arquivar um bug ?
Joachim Sauer
4
Sim, você definitivamente deve registrar um relatório de erro. Este é um bug muito sério!
Hot Licks
7
Sim, eu já enviei um relatório de erro para o Oracle (ID de erro 7196857) e ele aparecerá no banco de dados público de erros do Oracle em alguns dias.
Stanislav Poslavsky
6
Eu tentei com o Java 7 update 7 de 64 bits no Windows e não teve nenhum problema.
Peter Lawrey

Respostas:

42

Aqui nos deparamos com um bug no compilador JIT. O compilador determina que a matriz alocada é preenchida após a alocação Arrays.fill(...), mas a verificação de usos entre a alocação e o preenchimento está com defeito. Portanto, o compilador executa uma otimização ilegal - ignora o zeramento da matriz alocada.

Este bug é colocado no rastreador de erros do Oracle ( id 7196857 ). Infelizmente, não esperei nenhum esclarecimento da Oracle sobre os seguintes pontos. A meu ver, esse bug é específico do sistema operacional: é absolutamente reproduzível no Linux e Mac de 64 bits, mas, como vejo nos comentários, ele não é reproduzido regularmente no Windows (para versões semelhantes do JDK). Além disso, seria bom saber quando esse bug será corrigido.

No momento, existem apenas conselhos: não use o JDK1.7.0_04 ou posterior se você depende do JLS para matrizes recém-declaradas.

Atualização em 5 de outubro:

No novo Build 10 do JDK 7u10 (acesso antecipado) lançado em 04 de outubro de 2012, esse bug foi corrigido pelo menos para o Linux OS (não testei para outros). Obrigado a @Makoto, que descobriu que esse bug não está mais disponível para acesso público no banco de dados de erros do Oracle. Infelizmente, não sei pelos motivos que a Oracle o removeu do acesso público, mas está disponível no cache do Google . Além disso, esse bug chamou a atenção do Redhat: os identificadores do CVE CVE-2012-4420 ( bugzilla ) e CVE-2012-4416 ( bugzilla ) foram atribuídos a essa falha.

Stanislav Poslavsky
fonte
2
O ID do bug agora é inválido - você pode investigar isso?
Makoto
1
@ Makoto Estou confuso, uma vez que este bug estava no banco de dados de erros ontem. Não sei pela razão que a Oracle removeu esse bug do acesso público. Mas o Google lembrar webcache.googleusercontent.com/... Além disso, este bug também foi colocado no banco de dados de bug RedHat, uma vez que pode levar a uma CVE bugzilla.redhat.com/show_bug.cgi?id=856124
Stanislav Poslavsky
0

Fiz algumas alterações no seu código. Não é um problema de excesso de número inteiro. Veja o código, ele lança uma exceção em tempo de execução

    int[] a;
    int n = 0;
    for (int i = 0; i < 100000000; ++i) {
        a = new int[10];
        for (int f : a) {
            if (f != 0) {
                throw new RuntimeException("Array just after allocation: " + Arrays.toString(a));
            }
        }
        for (int ii = 0, len = a.length; ii < len; ii++)
            a[ii] = 0;
        for (int j = 0; j < a.length; ++j)
            a[j] = Integer.MAX_VALUE - 1;
        for (int j = 0; j < a.length; ++j)
            n++;
    }
Roberto Mereghetti
fonte
Windows 7 de 64 bits. Jdk 64 bit 1.7.0_07
Roberto Mereghetti 9/09/12