Java:int配列がゼロ以外の要素で初期化されます


130

JLSによると、int配列は初期化の直後にゼロで埋められる必要があります。しかし、そうではない状況に直面しています。このような動作は、JDK 7u4で最初に発生し、その後のすべての更新でも発生します(私は64ビット実装を使用しています)。次のコードは例外をスローします。

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

例外は、JVMがコードブロックのコンパイルを実行した後に発生し、-Xintフラグでは発生しません。さらに、Arrays.fill(...)ステートメント(このコードの他のすべてのステートメントと同様)が必要であり、このステートメントがない場合は例外は発生しません。この考えられるバグは、JVMの最適化に関係していることは明らかです。そのような行動の理由について何かアイデアはありますか?

更新:
HotSpot 64ビットサーバーVM、Gentoo Linux、Debian Linux(両方のカーネル3.0バージョン)、MacOS LionのJavaバージョン1.7.0_04から1.7.0_10でこの動作が見られます。このエラーは常に上記のコードで再現できます。32ビットJDKまたはWindowsでは、この問題をテストしていません。私はすでにOracleにバグレポートを送信しており(バグID 7196857)、数日以内にパブリックOracleバグデータベースに表示されます。

更新:
Oracleはこのバグを公開バグデータベースhttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857で公開しました


15
仕様に
準拠して

12
(少なくとも一部のプラットフォームでは)問題を確実に再現する明確に定義された例があるので、バグの報告を検討しましたか?
Joachim Sauer

4
はい、間違いなくバグレポートを提出してください。これは非常に深刻なバグです!
Hot Licks 2012

7
はい、すでにOracleにバグレポートを送信しています(バグID 7196857)。数日以内にOracleのパブリックバグデータベースに表示されます。
スタニスラフポスラスキー

6
WindowsでJava 7 Update 7 64ビットを使って試してみましたが、問題はありませんでした。
Peter Lawrey、2012

回答:


42

ここでは、JITコンパイラのバグに直面しています。コンパイラは、での割り当て後に割り当てられた配列が満たされると判断しArrays.fill(...)ますが、割り当てと充てんの間の使用のチェックに誤りがあります。したがって、コンパイラは不正な最適化を実行します-割り当てられた配列のゼロ化をスキップします。

このバグは、Oracle Bug Trackerに配置されます(バグID 7196857)。残念ながら、私は次の点についてOracleからの説明を待たなかった。ご覧のとおり、このバグはOS固有です。64ビットのLinuxとMacで完全に再現可能ですが、コメントからわかるように、Windowsでは(JDKの類似バージョンの場合)定期的に再現されません。さらに、このバグがいつ修正されるかを知っておくと便利です。

現在のところアドバイスがあります。新しく宣言された配列をJLSに依存している場合は、JDK1.7.0_04以降を使用しないでください。

10月5日の更新:

2012年10月4日にリリースされたJDK 7u10(早期アクセス)の新しいビルド10では、このバグは少なくともLinux OSで修正されました(他のものについてはテストしていません)。このバグがOracleバグデータベースのパブリックアクセスで利用できなくなったことを発見した@Makotoに感謝します。残念ながら、Oracleがパブリックアクセスから削除した理由はわかりませんが、Google キャッシュで利用できます。また、このバグはRedhatの注目を集めました。CVE識別子CVE-2012-4420bugzilla)およびCVE-2012-4416bugzilla)がこの欠陥に割り当てられました。


2
バグIDが無効になりました-調べていただけますか?

1
@誠このバグは昨日バグデータベースにあったので混乱しています。Oracleがこのバグをパブリックアクセスから削除した理由はわかりません。しかし、Googleは覚え webcache.googleusercontent.com/...を、それはCVEのにつながることができますので、このバグはまた、RedHatのバグデータベースに入れたさらにbugzilla.redhat.com/show_bug.cgi?id=856124
スタニスラフPoslavsky

0

コードに変更を加えました。整数オーバーフローの問題ではありません。コードを参照してください、それは実行時に例外をスローします

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

Windows 7 64ビット。Jdk 64ビット1.7.0_07
Roberto Mereghetti 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.