Java: int array menginisialisasi dengan elemen bukan nol

130

Menurut JLS, intarray harus diisi dengan nol setelah inisialisasi. Namun, saya dihadapkan pada situasi di mana tidak. Perilaku seperti itu terjadi pertama kali di JDK 7u4 dan juga terjadi di semua pembaruan selanjutnya (saya menggunakan implementasi 64-bit). Kode berikut melempar pengecualian:

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

Pengecualian terjadi setelah JVM melakukan kompilasi blok kode dan tidak muncul dengan -Xintflag. Selain itu, Arrays.fill(...)pernyataan (karena semua pernyataan lain dalam kode ini) diperlukan, dan pengecualian tidak terjadi jika tidak ada. Jelas bahwa kemungkinan bug ini terikat dengan beberapa optimasi JVM. Adakah ide untuk alasan perilaku seperti itu?

Memperbarui:
Saya melihat perilaku ini pada HotSpot 64-bit server VM, versi Java dari 1.7.0_04 ke 1.7.0_10 pada Gentoo Linux, Debian Linux (keduanya versi kernel 3.0) dan MacOS Lion. Kesalahan ini selalu dapat direproduksi dengan kode di atas. Saya tidak menguji masalah ini dengan JDK 32-bit atau pada Windows. Saya sudah mengirim laporan bug ke Oracle (bug id 7196857) dan akan muncul di database bug Oracle publik dalam beberapa hari.

Pembaruan:
Oracle menerbitkan bug ini di database bug publik mereka: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857

Stanislav Poslavsky
sumber
15
Saya akan mengatakan bug dalam implementasi jika tidak mengikuti spesifikasi
Petesh
12
Karena Anda memiliki contoh yang jelas yang mereproduksi masalah dengan andal (setidaknya pada beberapa platform), sudahkah Anda mempertimbangkan untuk mengajukan bug ?
Joachim Sauer
4
Ya, Anda harus mengajukan laporan bug. Ini adalah bug yang sangat serius!
Hot Licks
7
Ya, saya sudah mengirim laporan bug ke Oracle (bug id 7196857) dan akan muncul di database bug Oracle publik dalam beberapa hari.
Stanislav Poslavsky
6
Saya mencobanya dengan Java 7 update 7 64-bit di Windows dan tidak ada masalah.
Peter Lawrey

Jawaban:

42

Di sini kita dihadapkan dengan bug di JIT-compiler. Kompiler menentukan bahwa array yang dialokasikan diisi setelah alokasi masuk Arrays.fill(...), tetapi pemeriksaan untuk penggunaan antara alokasi dan pengisian salah. Jadi, kompiler melakukan optimasi ilegal - ia melewatkan zeroing dari array yang dialokasikan.

Bug ini ditempatkan di pelacak bug Oracle ( bug id 7196857 ). Sayangnya, saya tidak menunggu klarifikasi dari Oracle tentang poin-poin berikut. Seperti yang saya lihat, bug ini khusus untuk OS: benar-benar dapat diproduksi ulang di 64-bit Linux dan Mac, tetapi, seperti yang saya lihat dari komentar, bug ini tidak bereproduksi secara teratur di Windows (untuk versi JDK yang serupa). Selain itu akan menyenangkan untuk mengetahui kapan bug ini akan diperbaiki.

Hanya ada saran saat ini: jangan gunakan JDK1.7.0_04 atau lebih baru jika Anda bergantung pada JLS untuk array yang baru dideklarasikan.

Pembaruan pada 5 Oktober:

Dalam Build 10 baru dari JDK 7u10 (akses awal) dirilis pada 04 Oktober 2012, bug ini diperbaiki setidaknya untuk OS Linux (saya tidak menguji yang lain). Terima kasih kepada @Makoto, yang menemukan bahwa bug ini tidak lagi tersedia untuk akses publik di database bug Oracle. Sayangnya, saya tidak tahu karena alasan Oracle menghapusnya dari akses publik, tetapi itu tersedia di cache Google . Juga, bug ini telah menarik perhatian Redhat: pengidentifikasi CVE CVE-2012-4420 ( bugzilla ) dan CVE-2012-4416 ( bugzilla ) ditugaskan untuk cacat ini.

Stanislav Poslavsky
sumber
2
ID bug sekarang tidak valid - dapatkah Anda melihat ini?
Makoto
1
@ Makoto Saya bingung, karena bug ini ada di database bug kemarin. Saya tidak tahu karena alasan Oracle menghapus bug ini dari akses publik. Tetapi Google ingat webcache.googleusercontent.com/... Selain itu bug ini juga ditempatkan di database bug RedHat, karena bug ini dapat mengarah ke CVE bugzilla.redhat.com/show_bug.cgi?id=856124
Stanislav Poslavsky
0

Saya membuat beberapa perubahan pada kode Anda. Ini bukan masalah Integer overflow. Lihat kode, itu melempar pengecualian pada saat runtime

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