Java: la matriz int se inicializa con elementos distintos de cero

130

Según el JLS, una intmatriz debe rellenarse con ceros justo después de la inicialización. Sin embargo, me enfrento a una situación en la que no es así. Tal comportamiento ocurre primero en JDK 7u4 y también ocurre en todas las actualizaciones posteriores (uso la implementación de 64 bits). El siguiente código arroja una excepción:

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

La excepción ocurre después de que la JVM realiza la compilación del bloque de código y no surge con el -Xintindicador. Además, la Arrays.fill(...)declaración (como todas las demás declaraciones en este código) es necesaria, y la excepción no ocurre si está ausente. Está claro que este posible error está limitado con alguna optimización de JVM. ¿Alguna idea por la razón de tal comportamiento?

Actualización:
veo este comportamiento en la máquina virtual del servidor HotSpot de 64 bits, la versión Java de 1.7.0_04 a 1.7.0_10 en Gentoo Linux, Debian Linux (versión del kernel 3.0) y MacOS Lion. Este error siempre se puede reproducir con el código anterior. No probé este problema con un JDK de 32 bits o en Windows. Ya envié un informe de error a Oracle (ID de error 7196857) y aparecerá en la base de datos pública de errores de Oracle en unos días.

Actualización:
Oracle publicó este error en su base de datos pública de errores: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857

Stanislav Poslavsky
fuente
15
Yo diría error en la implementación si no está siguiendo la especificación
Petesh
12
Dado que tiene un ejemplo bien definido que reproduce de manera confiable el problema (al menos en algunas plataformas), ¿ha considerado presentar un error ?
Joachim Sauer
44
Sí, definitivamente debes presentar un informe de error. Este es un error muy serio!
Hot Licks
77
Sí, ya he enviado un informe de error a Oracle (ID de error 7196857) y aparecerá en la base de datos pública de errores de Oracle en unos días.
Stanislav Poslavsky
66
Lo probé con la actualización 7 de Java 7 de 64 bits en Windows y no tuve ningún problema.
Peter Lawrey

Respuestas:

42

Aquí nos enfrentamos a un error en el compilador JIT. El compilador determina que la matriz asignada se llena después de la asignación Arrays.fill(...), pero la verificación de usos entre la asignación y el llenado es defectuosa. Entonces, el compilador realiza una optimización ilegal: omite la puesta a cero de la matriz asignada.

Este error se coloca en el rastreador de errores de Oracle ( ID de error 7196857 ). Desafortunadamente, no esperé ninguna aclaración de Oracle sobre los siguientes puntos. Como veo, este error es específico del sistema operativo: es absolutamente reproducible en Linux y Mac de 64 bits, pero, como veo por los comentarios, no se reproduce regularmente en Windows (para versiones similares de JDK). Además, sería bueno saber cuándo se solucionará este error.

Por el momento solo hay consejos: no use JDK1.7.0_04 o posterior si depende de JLS para las matrices recientemente declaradas.

Actualización al 5 de octubre:

En el nuevo Build 10 del JDK 7u10 (acceso anticipado) lanzado el 4 de octubre de 2012, este error se corrigió al menos para el sistema operativo Linux (no probé para otro). Gracias a @Makoto, quien descubrió que este error ya no está disponible para el acceso público en la base de datos de errores de Oracle. Desafortunadamente, no sé por las razones por las que Oracle lo eliminó del acceso público, pero está disponible en el caché de Google . Además, este error ha llamado la atención de RedHat: los identificadores CVE CVE-2012 a 4.420 ( Bugzilla ) y CVE-2012-4416 ( Bugzilla ) fueron asignados a esta falla.

Stanislav Poslavsky
fuente
2
La identificación del error ahora no es válida. ¿Podría investigar esto?
Makoto
1
@ Makoto Estoy confundido, ya que este error estaba en la base de datos de errores ayer. No sé por la razón por la que Oracle eliminó este error del acceso público. Pero Google recuerda webcache.googleusercontent.com/… Además, este error también se colocó en la base de datos de errores de RedHat, ya que puede conducir a un CVE bugzilla.redhat.com/show_bug.cgi?id=856124
Stanislav Poslavsky
0

Hice algún cambio en tu código. No es un problema de desbordamiento de enteros. Ver el código, arroja una excepción en tiempo de ejecución

    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
fuente
Windows 7 de 64 bits. Jdk 64 bit 1.7.0_07
Roberto Mereghetti