Java: le tableau int s'initialise avec des éléments différents de zéro

130

Selon le JLS, un inttableau doit être rempli de zéros juste après l'initialisation. Cependant, je suis confronté à une situation où ce n'est pas le cas. Un tel comportement se produit en premier dans JDK 7u4 et se produit également dans toutes les mises à jour ultérieures (j'utilise une implémentation 64 bits). Le code suivant lève 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 effectué la compilation du bloc de code et ne se produit pas avec l' -Xintindicateur. En outre, l' Arrays.fill(...)instruction (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 éventuel est lié à une certaine optimisation JVM. Des idées pour la raison d'un tel comportement?

Mise à jour:
Je vois ce comportement sur la VM serveur HotSpot 64 bits, la 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 bogue à Oracle (id de bogue 7196857) et il apparaîtra dans la base de données publique de bogues 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

Stanislav Poslavsky
la source
15
Je dirais un bug dans la mise en œuvre si elle ne suit pas les spécifications
Petesh
12
Puisque vous avez un exemple bien défini qui reproduit de manière fiable le problème (au moins sur certaines plates-formes), avez-vous envisagé de déposer un bogue ?
Joachim Sauer
4
Oui, vous devez absolument déposer un rapport de bogue. C'est un bug très sérieux!
Hot Licks
7
Oui, j'ai déjà envoyé un rapport de bogue à Oracle (id de bogue 7196857) et il apparaîtra dans la base de données publique de bogues d'Oracle dans quelques jours.
Stanislav Poslavsky
6
Je l'ai essayé avec Java 7 update 7 64 bits sur Windows et cela n'a pas eu de problème.
Peter Lawrey

Réponses:

42

Ici, nous sommes confrontés à un bogue dans le compilateur JIT. Le compilateur détermine que le tableau alloué est rempli après l'allocation Arrays.fill(...), mais la vérification des utilisations entre l'allocation et le remplissage est erronée. Ainsi, le compilateur effectue une optimisation illégale - il ignore la remise à zéro du tableau alloué.

Ce bogue est placé dans Oracle Bug Tracker ( id de bogue 7196857 ). Malheureusement, je n'ai pas attendu d'éclaircissements 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 et Mac 64 bits, mais, comme je le vois dans les commentaires, il ne se reproduit pas régulièrement sous Windows (pour des versions similaires de JDK). De plus, il serait bon de savoir quand ce bug sera corrigé.

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

Mise à jour le 5 octobre:

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

Stanislav Poslavsky
la source
2
L'ID de bogue est maintenant invalide - pourriez-vous examiner cela?
Makoto
1
@Makoto Je suis confus, car ce bogue était dans la base de données de bogues hier. Je ne sais pas pourquoi Oracle a supprimé ce bogue de l'accès public. Mais Google se souvient de webcache.googleusercontent.com/ ... De plus, ce bogue a également été placé dans la base de données de bogues RedHat, car il peut conduire à un bugzilla.redhat.com/show_bug.cgi?id=856124
Stanislav Poslavsky
0

J'ai fait quelques changements dans votre code. Ce n'est pas un problème de débordement d'entier. Voir le code, il lève une exception lors 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++;
    }
Roberto Mereghetti
la source
Windows 7 64 bits. Jdk 64 bit 1.7.0_07
Roberto Mereghetti