web-dev-qa-db-fra.com

Java: int tableau initialise avec des éléments non nuls

Selon le JLS, un tableau 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. Un tel comportement se produit d'abord 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'indicateur -Xint. En outre, l'instruction 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 limité par une optimisation JVM. Des idées pour la raison d'un tel comportement?

Mise à jour:
Je vois ce comportement sur la machine virtuelle du serveur HotSpot 64 bits, Java de 1.7.0_04 à 1.7.0_10 sous 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 Oracle public base de données de bogues en quelques jours.

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

130

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

Ce bug est placé dans Oracle bug tracker ( bug id 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 sur Windows (pour des versions similaires de JDK). De plus, ce serait bien 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 une version ultérieure si vous dépendez de JLS pour les tableaux nouvellement déclarés.

Mise à jour au 5 octobre: ​​

Dans le nouveau Build 1 du JDK 7u10 (accès anticipé) 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 constaté que ce bogue n'était plus disponible pour l'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 Google cache . En outre, ce bogue a attiré l'attention de Redhat: les identifiants CVE CVE-2012-442 ( bugzilla ) et CVE-2012-4416 ( bugzilla ) ont été affectés à cette faille.

42
Stanislav Poslavsky

J'ai fait quelques changements dans votre code. Ce n'est pas un problème de dépassement 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++;
    }
0
Roberto Mereghetti