Java: Das int-Array wird mit Elementen ungleich Null initialisiert

130

Laut JLS sollte ein intArray unmittelbar nach der Initialisierung mit Nullen gefüllt werden. Ich bin jedoch mit einer Situation konfrontiert, in der dies nicht der Fall ist. Ein solches Verhalten tritt zuerst in JDK 7u4 und auch in allen späteren Updates auf (ich verwende die 64-Bit-Implementierung). Der folgende Code löst eine Ausnahme aus:

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

Die Ausnahme tritt auf, nachdem die JVM die Kompilierung des Codeblocks durchgeführt hat, und tritt nicht mit dem -XintFlag auf. Darüber hinaus ist die Arrays.fill(...)Anweisung (wie alle anderen Anweisungen in diesem Code) erforderlich, und die Ausnahme tritt nicht auf, wenn sie nicht vorhanden ist. Es ist klar, dass dieser mögliche Fehler mit einigen JVM-Optimierungen verbunden ist. Irgendwelche Ideen wegen eines solchen Verhaltens?

Update:
Ich sehe dieses Verhalten auf HotSpot 64-Bit-Server-VM, Java-Version von 1.7.0_04 bis 1.7.0_10 unter Gentoo Linux, Debian Linux (beide Kernel 3.0-Version) und MacOS Lion. Dieser Fehler kann immer mit dem obigen Code reproduziert werden. Ich habe dieses Problem nicht mit einem 32-Bit-JDK oder unter Windows getestet. Ich habe bereits einen Fehlerbericht an Oracle gesendet (Fehler-ID 7196857), der in wenigen Tagen in der öffentlichen Oracle-Fehlerdatenbank angezeigt wird.

Update:
Oracle hat diesen Fehler in seiner öffentlichen Fehlerdatenbank veröffentlicht: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857

Stanislav Poslavsky
quelle
15
Ich würde sagen, Fehler in der Implementierung, wenn es nicht der Spezifikation
folgt
12
Haben Sie überlegt , einen Fehler einzureichen, da Sie ein genau definiertes Beispiel haben, das das Problem zuverlässig reproduziert (zumindest auf einigen Plattformen) ?
Joachim Sauer
4
Ja, Sie sollten auf jeden Fall einen Fehlerbericht einreichen. Dies ist ein sehr schwerwiegender Fehler!
Hot Licks
7
Ja, ich habe bereits einen Fehlerbericht an Oracle gesendet (Fehler-ID 7196857), der in einigen Tagen in der öffentlichen Oracle-Fehlerdatenbank angezeigt wird.
Stanislav Poslavsky
6
Ich habe es mit Java 7 Update 7 64-Bit unter Windows versucht und es gab kein Problem.
Peter Lawrey

Antworten:

42

Hier sind wir mit einem Fehler im JIT-Compiler konfrontiert. Der Compiler stellt fest, dass das zugewiesene Array nach der Zuweisung gefüllt Arrays.fill(...)ist, die Überprüfung der Verwendung zwischen der Zuordnung und der Füllung jedoch fehlerhaft ist. Der Compiler führt also eine unzulässige Optimierung durch - er überspringt das Nullstellen des zugewiesenen Arrays.

Dieser Fehler wird in Oracle Bug Tracker ( Fehler-ID 7196857 ) platziert. Leider habe ich nicht auf Klarstellungen von Oracle zu den folgenden Punkten gewartet. Wie ich sehe, ist dieser Fehler betriebssystemspezifisch: Er ist unter 64-Bit-Linux und Mac absolut reproduzierbar, aber wie ich aus den Kommentaren sehe, wird er unter Windows nicht regelmäßig reproduziert (für ähnliche Versionen von JDK). Außerdem wäre es schön zu wissen, wann dieser Fehler behoben wird.

Derzeit gibt es nur Ratschläge: Verwenden Sie JDK1.7.0_04 oder höher nicht, wenn Sie für neu deklarierte Arrays auf JLS angewiesen sind.

Update am 5. Oktober:

In dem neuen Build 10 des JDK 7u10 (früher Zugriff), das am 04. Oktober 2012 veröffentlicht wurde, wurde dieser Fehler zumindest für Linux-Betriebssysteme behoben (ich habe nicht für andere getestet). Vielen Dank an @Makoto, der festgestellt hat, dass dieser Fehler nicht mehr für den öffentlichen Zugriff in der Oracle-Fehlerdatenbank verfügbar ist. Leider weiß ich nicht, warum Oracle es aus dem öffentlichen Zugriff entfernt hat, aber es ist im Google- Cache verfügbar . Auch dieser Fehler hat die Aufmerksamkeit von Redhat auf sich gezogen: Die CVE-Kennungen CVE-2012-4420 ( Bugzilla ) und CVE-2012-4416 ( Bugzilla ) wurden diesem Fehler zugewiesen.

Stanislav Poslavsky
quelle
2
Die Fehler-ID ist jetzt ungültig - können Sie dies untersuchen?
Makoto
1
@ Makoto Ich bin verwirrt, da dieser Fehler gestern in der Fehlerdatenbank war. Ich weiß nicht aus dem Grund, warum Oracle diesen Fehler aus dem öffentlichen Zugriff entfernt hat. Aber Google erinnert sich an webcache.googleusercontent.com/…. Zusätzlich wurde dieser Fehler auch in die RedHat- Fehlerdatenbank aufgenommen , da er zu einem CVE führen kann. Bugzilla.redhat.com/show_bug.cgi?id=856124
Stanislav Poslavsky
0

Ich habe Ihren Code geändert. Es ist kein Problem des Integer-Überlaufs. Siehe den Code, er löst zur Laufzeit eine Ausnahme aus

    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
quelle
Windows 7 64 Bit. Jdk 64 Bit 1.7.0_07
Roberto Mereghetti