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


De acuerdo con el JLS, un array int debe ser llenado por ceros justo después de la inicialización. Sin embargo, me enfrento a una situación en la que no lo es. Este 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 lanza 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 -Xint flag. Además, la instrucción Arrays.fill(...) (como todas las demás instrucciones en este código) es necesario, y la excepción no pasa si está ausente. Está claro que este posible error está limitado con alguna optimización JVM. ¿Alguna idea por la razón de tal comportamiento?

Actualización:
Veo este comportamiento en HotSpot 64-bit server VM, Java version from 1.7.0_04 to 1.7.0_10 on Gentoo Linux, Debian Linux (both kernel 3.0 version) and 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 (bug id 7196857) y aparecerá en la base de datos pública de errores de Oracle en pocos 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

Author: Stanislav Poslavsky, 2012-09-07

2 answers

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 en Arrays.fill(...), pero la comprobación de usos entre la asignación y el relleno es defectuosa. Por lo tanto, el compilador realiza una optimización ilegal: omite la puesta a cero de la matriz asignada.

Este error se coloca en Oracle bug tracker (bug id 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 en los comentarios, no se reproduce regularmente en Windows (para versiones similares de JDK). Además, sería bueno saber cuándo se corregirá este error.

Solo hay consejos en este momento: no use JDK1.7.0_04 o posterior si depende de JLS para los arrays recién declarados.

Actualización en octubre 5:

En el nuevo Build 10 del JDK 7u10 (acceso anticipado) lanzado el 04 de octubre, 2012, este error se corrigió al menos para el sistema operativo Linux (no probé para otros). Gracias a @ Makoto, quien descubrió que este error ya no está disponible para el acceso público en Oracle bug database. Desafortunadamente, no sé por qué Oracle lo eliminó del acceso público, pero está disponible en Google cache. También, este error ha llamado la atención de Redhat: los identificadores CVE CVE-2012-4420 (bugzilla) y CVE-2012-4416 (bugzilla) fueron asignados a este defecto.

 42
Author: Stanislav Poslavsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-05 15:08:37

Hice algunos cambios en tu código. No es un problema de desbordamiento de enteros. Ver el código, lanza 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++;
    }
 0
Author: Roberto Mereghetti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-09 10:03:46