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

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

更新:
Gentoo Linux、Debian Linux (両方ともカーネル 3.0 バージョン)、および MacOS Lion 上の HotSpot 64 ビット サーバー VM、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

4

2 に答える 2

42

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

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

現時点でのアドバイスは1つだけです。新しく宣言された配列をJLSに依存している場合は、JDK1.7.0_04以降を使用しないでください。

10月5日の更新:

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

于 2012-09-11T17:59:15.810 に答える
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++;
    }
于 2012-09-09T09:04:38.247 に答える