130 votes

Java : un tableau d'int s'initialise avec des éléments non nuls

Selon la JLS, un int doit être rempli par des zéros juste après l'initialisation. Cependant, je suis confronté à une situation où ce n'est pas le cas. Ce comportement est apparu pour la première fois dans le JDK 7u4, puis dans toutes les mises à jour ultérieures (j'utilise une implémentation 64 bits). Le code suivant lance une exception :

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

L'exception se produit après que la JVM a compilé le bloc de code et ne se produit pas avec la fonction -Xint drapeau. En outre, le Arrays.fill(...) (comme toutes les autres instructions de ce code) est nécessaire, et l'exception ne se produit pas si elle est absente. Il est clair que ce bogue possible est lié à une optimisation de la JVM. Une idée de la raison d'un tel comportement ?

Mise à jour :
Je constate ce comportement sur HotSpot 64-bit server VM, version Java de 1.7.0_04 à 1.7.0_10 sur Gentoo Linux, Debian Linux (les deux versions du noyau 3.0) et MacOS Lion. Cette erreur peut toujours être reproduite avec le code ci-dessus. Je n'ai pas testé ce problème avec un JDK 32 bits ou sous Windows. J'ai déjà envoyé un rapport de bug à Oracle (bug id 7196857) et il apparaîtra dans la base de données publique des bugs d'Oracle dans quelques jours.

Mise à jour :
Oracle a publié ce bogue dans sa base de données publique de bogues : http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857

42voto

Stanislav Poslavsky Points 1134

Nous sommes ici confrontés à un bogue dans le compilateur JIT. Le compilateur détermine que le tableau alloué est rempli après l'allocation en Arrays.fill(...) mais le contrôle des utilisations entre l'allocation et le remplissage est défectueux. Ainsi, le compilateur effectue une optimisation illégale - il saute la mise à zéro du tableau alloué.

Ce bogue est placé dans le système de suivi des bogues d'Oracle ( bug id 7196857 ). Malheureusement, je n'ai pas attendu d'éclaircissements de la part d'Oracle sur les points suivants. Comme je le vois, ce bogue est spécifique au système d'exploitation : il est absolument reproductible sur Linux 64 bits et Mac, mais, comme je le vois dans les commentaires, il ne se reproduit pas régulièrement sous Windows (pour des versions similaires du JDK). En outre, il serait bon de savoir quand ce bogue sera corrigé.

Il n'y a qu'un conseil à donner pour l'instant : n'utilisez pas le JDK1.7.0_04 ou une version ultérieure si vous dépendez de JLS pour les tableaux nouvellement déclarés.

Mise à jour au 5 octobre :

Dans la nouvelle Construire 10 du JDK 7u10 (early access) sorti le 04 octobre 2012, ce bug a été corrigé au moins pour Linux OS (je n'ai pas testé pour les autres). Merci à @Makoto, qui a trouvé que ce bogue n'est plus disponible en accès public dans la base de données des bogues d'Oracle. Malheureusement, je ne sais pas pour quelles raisons Oracle l'a retiré de l'accès public, mais il est disponible sur Google. cache . Ce bogue a également attiré l'attention de Redhat : les identifiants CVE CVE-2012-4420 ( bugzilla ) et CVE-2012-4416 ( bugzilla ) ont été affectés à cette faille.

0voto

J'ai apporté quelques modifications à votre code. Il ne s'agit pas d'un problème de dépassement d'entier. Voir le code, il lance une exception au moment de l'exécution

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X